使用Class vs Module在Ruby中打包代码

时间:2011-12-13 22:00:50

标签: ruby class module mixins

假设我有一堆没有持久状态的相关函数,比如字符串差异包中的各种操作。我可以在类或模块中定义它们(使用self)并且可以以完全相同的方式访问它们:

class Diff
  def self.diff ...
  def self.patch ...
end

module Diff
  def self.diff ...
  def self.patch ...
end
然后我可以做Diff.patch(...)。哪个'更好'(或'正确')?

我需要将它们分组的主要原因是命名空间问题,常用的函数名称都在别处使用。

编辑:将示例从矩阵更改为差异。 Matrix是一个可怕的例子,因为它 有状态,每个人都开始解释为什么把它们作为方法编写而不是回答实际问题更好。 :(

5 个答案:

答案 0 :(得分:3)

模块和类之间的主要区别在于您无法实例化模块;你做不到obj = MyModule.new。你的问题的假设是你不想实例化任何东西,所以我建议你只使用一个模块。

你仍然需要重新考虑你的方法:不是使用数组或你正在做的任何代表矩阵的数组,而是让你自己的类来表示矩阵或find a good class that someone else has already written更优雅。

答案 1 :(得分:3)

在您的两个示例中,您实际上并未在ClassModule中定义方法;你是在一个恰好是ClassModule的对象上定义单例方法,但可能只是关于任何对象。以下是String

的示例
Diff = "Use me to access really cool methods"

def Diff.patch
  # ...
end

您可以执行其中任何操作,但这样做可行,但将相关方法分组的最佳方法是使用Module作为常规实例方法(即不使用self.):

module Diff
  extend self  # This makes the instance methods available to the Diff module itself
  def diff ... # no self.
  def patch ...
end

现在你可以:

  • 在任何类(使用include Diff)或任何对象(使用extend Diff
  • 中使用此功能
  • 此用途的一个示例是extend self行,可以调用Diff.patch
  • 甚至在全局命名空间中使用这些方法

例如,在irb

class Foo
  include Diff
end
Foo.new.patch # => calls the patch method
Diff.patch    # => also calls Diff.patch
include Diff  # => now you can call methods directly:
patch         # => also calls the patch method

注意extend self将“修改”Diff模块对象本身,但它不会对模块的包含产生任何影响。同样的事情发生在def self.foo上,foo将无法用于包括它的任何类。简而言之,只有Diff的实例方法是使用include(或extend)导入的,而不是单例方法。只有继承类才能提供实例和单例方法的继承。

当你真的希望包含一个模块来提供实例方法和单例方法时,它并不容易。您必须使用self.included挂钩:

module Foo
  def some_instance_method; end

  module ClassMethods
    def some_singleton_method; end
  end

  def self.included(base)
    base.send :extend, ClassMethods
  end

  def self.will_not_be_included_in_any_way; end
end

class Bar
  include Foo
end
# Bar has now instance methods:
Bar.new.some_instance_method  # => nil
# and singleton methods:
Bar.some_singleton_method   # => nil

答案 2 :(得分:2)

Ruby模块用于指定行为,相关功能的部分。

Ruby Classes用于指定状态和行为,一个单一的实体。

软件设计中存在一种格言,即代码是一种负担,因此尽可能使用较少的代码。在Ruby的情况下,代码行的差异是cero。所以你可以使用任何一种方式(如果你不需要保存状态)

如果您想成为纯粹主义者,请使用模块,因为您不会使用状态功能。但我不会说使用类是错误的。

作为一个琐事信息:在Ruby中,一个类是一种模块。

http://www.ruby-doc.org/core-1.9.3/Class.html

答案 3 :(得分:1)

以下也适用

Matrix = Object.new

def Matrix.add ...
def Matrix.equals ...

那是因为所谓的“类方法”只是添加到单个对象的方法,而且对象类的内容并不重要。

答案 4 :(得分:1)

作为一种形式,模块更正确。您仍然可以创建类的实例,即使它只有类方法。您可以将此处的模块视为C#或Java的静态类。类也始终具有与实例相关的方法(newallocate等)。使用模块。类方法通常与对象有关(创建它们,操纵它们)。