假设我有一堆没有持久状态的相关函数,比如字符串差分包中的各种操作。我可以在类或模块中定义它们(使用 self
),并且可以用完全相同的方式访问它们:
class Diff
def self.diff ...
def self.patch ...
end
或
module Diff
def self.diff ...
def self.patch ...
end
然后我可以执行 Diff.patch(...)
。哪个“更好”(或“正确”)?
我需要将它们分组的主要原因是命名空间问题,常见的函数名称都在别处使用。
编辑:将示例从矩阵更改为差异。 Matrix 是一个糟糕的例子,因为它确实有状态,每个人都开始解释为什么最好将它们写成方法而不是回答实际问题。 :(
最佳答案
在您的两个示例中,您实际上并未在 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
钩子(Hook):
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
关于ruby - 使用类与模块在 Ruby 中打包代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8496803/