假设我有一堆没有持久状态的相关函数,比如字符串差异包中的各种操作。我可以在类或模块中定义它们(使用self
)并且可以以完全相同的方式访问它们:
class Diff
def self.diff ...
def self.patch ...
end
或
module Diff
def self.diff ...
def self.patch ...
end
然后我可以做Diff.patch(...)
。哪个'更好'(或'正确')?
我需要将它们分组的主要原因是命名空间问题,常用的函数名称都在别处使用。
编辑:将示例从矩阵更改为差异。 Matrix是一个可怕的例子,因为它 有状态,每个人都开始解释为什么把它们作为方法编写而不是回答实际问题更好。 :(
答案 0 :(得分:3)
模块和类之间的主要区别在于您无法实例化模块;你做不到obj = MyModule.new
。你的问题的假设是你不想实例化任何东西,所以我建议你只使用一个模块。
你仍然需要重新考虑你的方法:不是使用数组或你正在做的任何代表矩阵的数组,而是让你自己的类来表示矩阵或find a good class that someone else has already written更优雅。
答案 1 :(得分:3)
在您的两个示例中,您实际上并未在Class
或Module
中定义方法;你是在一个恰好是Class
或Module
的对象上定义单例方法,但可能只是关于任何对象。以下是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中,一个类是一种模块。
答案 3 :(得分:1)
以下也适用
Matrix = Object.new
def Matrix.add ...
def Matrix.equals ...
那是因为所谓的“类方法”只是添加到单个对象的方法,而且对象类的内容并不重要。
答案 4 :(得分:1)
作为一种形式,模块更正确。您仍然可以创建类的实例,即使它只有类方法。您可以将此处的模块视为C#或Java的静态类。类也始终具有与实例相关的方法(new
,allocate
等)。使用模块。类方法通常与对象有关(创建它们,操纵它们)。