9

之前有人问过类似的问题,但我特别问的是使用组合作为使用模块 mixins 的替代方法。

class Helper
  def do_somthing
  end
end

如果我需要“使用”一个类但不继承它,我只需编写它并使用它。

class MyStuff
  def initialize
    helper = Helper.new
    helper.do_something
  end
end

我为什么要为此创建一个模块:

 module Helper
   def do_something
   end
 end

class MyStuff
  include Helper
end

我看到的唯一区别是,如果我使用模块,周围不会有很多Helper物体。但是我没有看到周围有更多物体而不是更大物体的任何东西。

此外,我不知道将来是否需要对它进行子类化。那么我如何决定我的库的用户是想要使用模块 mixin,还是想要使用组合呢?

4

4 回答 4

18

Helper当和类之间的关系MyStuff是所有权关系时,使用组合。这被称为“拥有”关系。例如,假设您有Person一个班级和一个Car班级。你会使用组合,因为一个人有车:

class Person
  def initialize
    @car = Car.new
  end
end

class Car
  def accelerate
    # implementation
  end
end

Helper “表现得像” MyStuff时,使用模块 mixinHelper,在这种情况下,扮演的角色MyStuff这与“is-a”关系有点不同,这意味着您应该使用传统继承。例如,假设我们有一个Person类和一个Sleeper模块。一个人有时会扮演睡眠者的角色,但其他物体也是如此——例如Dog,,Frog甚至可能Computer。这些其他类中的每一个都代表可以睡觉的东西。

module Sleeper
  def go_to_sleep
    # implementation
  end
end

class Person
  include Sleeper
end

class Computer
  include Sleeper
end

Sandi Metz 的 Practical Object-Oriented Design in Ruby是这些主题的绝佳资源。

于 2014-12-18T14:39:44.667 回答
2

这是“<a href="http://en.wikipedia.org/wiki/Duck_typing" rel="nofollow">Duck Typing”的问题。如果您希望您的班级表现得像一个Helper,那么您就这样做了include。无论您是要封装 Helper行为,正确的选择是require.

Enumerable在一起,你通过实现唯一的方法给你的类大量的each方法。包装Array您可能会向其他人隐藏迭代并将其仅用于保存您的数据。反之亦然。

于 2013-04-02T03:13:47.377 回答
1

模块 mixin 更像是多重继承,所以遵循通常的继承与组合规则——is-a 或 has-a。顺便说一句,它是include Helper,不是require 'Helper'

于 2013-04-02T02:24:48.083 回答
0

有几点我可以分享:

  • 如果你需要在不同的类和模块中共享共同的行为,你应该把它做成模块,以便以后你可以include在任何你喜欢的地方使用模块。它也将有助于测试,因为它已经干了。

  • 在责任的情况下,您可以将其制成新的模块,以明确理解并提高代码库的可读性。这将有助于减少应该易于遵循和维护的主要类的大小。

您可能会注意到一件事,它为您的where本身include添加了功能。instanceextendClass

于 2013-04-02T02:33:58.917 回答