“Ruby方式”(mixins和类重新开放)与dependency injection

在研究mixins与dependency injection时,我经常听到“Ruby方式”这个短语。 开发人员通常会说些什么

Ruby允许您重新打开类并重新定义方法意味着您可以在测试时轻松地将新引用“注入”代码中。

(见http://weblog.jamisbuck.org/2007/7/29/net-ssh-revisited#6 )

但测试不是我主要考虑的问题; 我担心的是课堂重用。 我想要可以在多个企业级Rails应用程序中重用的类。

那么REUSING类会发生什么? 使用mixins和重新打开类似乎并没有提供一种方法来编写类,使它们与特定于应用程序的细节分离,而无需额外的工作。 但也许我错了。 如果我是,有人可以提供一个链接到包含示例代码的文章,该文章清楚地解释了如何使用mixins和重新打开类正确地完成此操作吗?

例如,这里的类Foo耦合到类Logger:

class Foo def initialize @logger = new_logger end def new_logger Logger.new end end 

是的,我可以重新打开Foo并重新定义new_logger,但我无法相信这被认为是编写可由多个Rails应用程序使用的可重用类的现实标准方法。

实际上,当我从Java世界来到ruby世界时,我感兴趣的第一件事是他们如何管理依赖关系。 当时我在所有java项目中使用Google Guice,我的灵感来自于其巧妙的设计和易用性。 我在ruby中做的第一件事就是我自己的DI容器, 它与Google Guice具有大致相同的function – ( 它仍然在github上,但它已经过时了)。

但是在使用Rails / Ruby两年后,我认为这里不需要DI。 关于rubyDI的好文章是http://weblog.jamisbuck.org/2008/11/9/legos-play-doh-and-programming它实际上是一篇关于为什么其中一个作者不需要DI的文章。第一个用于ruby的DI容器。 绝对值得一读。

好吧,因为我们可以在Ruby中重新打开类并不意味着我们总是必须这样做,你可以把重新开放的类作为最后的方法。 你有一个库可以完成你需要的一切,除了一个方法,而不是分叉整个库修补它并使用你的分支,你可以简单地重新打开类,重新定义方法,你再次开展业务。 这不是你不会做的事情,但有能力这样做是非常有用的。

说完所有这些,在Ruby中我们有一个概念几乎总是可以替代dependency injection – 鸭子打字。 由于没有类型检查,您可以将任何对象传递给函数,只要该对象具有该函数所期望的方法,一切都将正常工作。

让我们看看你的例子 – 它不是真正有利于dependency injection的类,你不会在Java中编写它,例如,如果你想注入一些依赖项。 您只能通过构造函数或通过getter和setter注入。 所以让我们以这种方式重写这个类:

 class Foo def initialize(logger) @logger = logger end end 

我们现在可以更好地注入/传入一个记录器到我们的Foo类中。 让我们添加一个使用此记录器来演示的方法:

 class Foo def initialize(logger) @logger = logger end def do_stuff @logger.info("Stuff") end end 

在java中,如果你想用不同类型的记录器创建Foo对象,那么所有这些记录器都必须在字面意义上实现相同的接口(例如, public class logger implements Loggable ),或者至少是子类。 但是在Ruby中,只要对象有一个接受字符串的info方法,你就可以将它传递给构造函数,并且Ruby会继续快乐地进行操作。 让我们来说明:

 class Logger def info(some_info) end end class Widget def info(some_widget_info) end end class Lolcat def info(lol_string) end end Foo.new(Logger.new).do_stuff Foo.new(Widget.new).do_stuff Foo.new(Lolcat.new).do_stuff 

由于Foo类的上述所有3个实例都调用了do_stuff方法,所以一切都会正常工作。

正如你从这个例子中看到的那样,坚持OO设计的原则仍然很重要,但Ruby对它接受的内容的限制较少,只要正确的方法存在,一切都会好的。

根据你的看法,鸭子打字要么使dependency injection完全不相关,要么使它比以前更强大。

简单的答案是Ruby语言中的任何内容都无法阻止您编写可重用的类。 使用混合和类重新开放的常用方法并不一定会促进它,但语言实际上并没有阻止其他方法。 把“Ruby Way”想象成“Ruby可以做的事情”的一个子集

也就是说,我知道通常最好用语言结构来强制执行设计决策,据我所知(我将警告你,这个主题还远未完成)DI目前不是核心的Ruby主义。 有点谷歌搜索给我发了一些关于这个主题的文章,但是让我相信,如果你愿意的话,有些库可以将DI添加到Ruby中(尽管它们似乎受到了许多Rubyist的批评)。 信息性文章包括这 两个 , 这个问题 。 希望有所帮助。

关于如何在Ruby中使用IoC的文章你低估了IoC的强大function

有工作样品。

UPDATE

链接现在已经死了,这里是源代码https://github.com/alexeypetrushin/rubylang/blob/master/draft/you-underestimate-the-power-of-ioc.md

我使用IoC作为我的Web框架的一部分,我有点重新创建了Ruby on Rails并且它有效,但是,它不会比RoR具有显着的优势,具有类似的特性。 所以,它成了一种负担,我放弃了它,一些细节http://petrush.in/blog/2011/rad-web-framework 。

我完全同意。 动态语言不能替代dependency injection。 没有什么能阻止你为动态语言编写一个。 这是Smalltalk的dependency injection框架: http : //www.squeaksource.com/Seuss.html