“Ruby方式”(mixins和类重新开放)与依赖注入

时间:2011-08-15 13:14:40

标签: ruby-on-rails ruby dependency-injection mixins

在研究mixins与依赖注入时,我经常听到“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应用程序使用的可重用类的现实标准方法。

6 个答案:

答案 0 :(得分:9)

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

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

答案 1 :(得分:5)

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

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

让我们看看你的例子 - 它不是真正有利于依赖注入的类,你不会在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对它接受的内容的限制较少,只要正确的方法存在,一切都会好的。

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

答案 2 :(得分:2)

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

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

答案 3 :(得分:2)

关于如何在Ruby You underestimate the power of IoC

中使用IoC的文章

使用工作样本。

更新

链接现在已经死了,这是源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

答案 4 :(得分:1)

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

答案 5 :(得分:0)

我认为 DI 与动态/静态语言无关。 Image 你有一组类,它们相互依赖;现在您要创建其中一个类的对象,您可能需要创建许多其他对象来为您要创建的对象准备依赖项。

DI 在这种情况下非常有用:您在编码时已经告诉容器所有依赖关系。现在您只需从容器中请求一个对象。 Container 会帮助创建所有的依赖和依赖的依赖来创建你想要的对象。

但是最好的容器是什么???