我们什么时候使用ruby模块和使用类组合?

时间:2013-04-02 01:46:53

标签: ruby inheritance multiple-inheritance composition 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 个答案:

答案 0 :(得分:15)

如果HelperMyStuff类之间的关系属于所有权,请使用合成。这被称为“has-a”关系。例如,假设您有Person类和Car类。你会使用作文,因为一个人有车:

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

class Car
  def accelerate
    # implementation
  end
end

Helper “的行为类似于” MyStuff时,请使用模块mixin 。在这种情况下,Helper采用MyStuff角色。这与“is-a”关系略有不同,这意味着您应该使用传统继承。例如,假设我们有一个Person类和一个Sleeper模块。一个人有时扮演一个睡眠者的角色,但其他对象也是如此 - DogFrog或甚至Computer的实例。其他每一类都代表着可以入睡的东西。

module Sleeper
  def go_to_sleep
    # implementation
  end
end

class Person
  include Sleeper
end

class Computer
  include Sleeper
end

Sandi Metz的实用Object-Oriented Design in Ruby是这些主题的优秀资源。

答案 1 :(得分:2)

这是“Duck Typing”的问题。如果您希望自己的课程行为类似于Helper,则可以include。无论您是encapsulate Helper行为,正确的选择都是require

混合Enumerable,您可以通过实施唯一的each方法为您的课程提供大量方法。包装Array您可以隐藏其他人的迭代并将其用于仅保留您的数据。反之亦然。

答案 2 :(得分:0)

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

答案 3 :(得分:0)

我可以分享一些内容:

  • 如果您需要在不同的类和模块中共享共同的行为,您应该将其转换为模块,以便以后只需include模块就可以了。它也有助于测试,因为它已经干了。

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

您可能会注意到includeinstance添加了extend Class对{{1}}本身的功能。