使用类vs模块在Ruby中打包代码
假设我有一组没有持久状态的相关函数,比如字符串差分包中的各种操作。我可以在类或模块中定义它们(使用使用类vs模块在Ruby中打包代码,ruby,class,module,mixins,Ruby,Class,Module,Mixins,假设我有一组没有持久状态的相关函数,比如字符串差分包中的各种操作。我可以在类或模块中定义它们(使用self),它们的访问方式完全相同: class Diff def self.diff ... def self.patch ... end 或 然后我可以做Diff.patch(…)。哪一个更好(或正确) 我需要将它们分组的主要原因是名称空间问题,常见的函数名都在其他地方使用 编辑:将示例从matrix更改为diff。matrix是一个糟糕的示例,因为它确实有状态,每个人都开始解释为什么
self
),它们的访问方式完全相同:
class Diff
def self.diff ...
def self.patch ...
end
或
然后我可以做Diff.patch(…)
。哪一个更好(或正确)
我需要将它们分组的主要原因是名称空间问题,常见的函数名都在其他地方使用
编辑:将示例从matrix更改为diff。matrix是一个糟糕的示例,因为它确实有状态,每个人都开始解释为什么将它们作为方法编写比回答实际问题更好(Ruby模块用于指定行为和相关功能 Ruby类用于指定状态和行为,这是一个单一的实体 软件设计中有一条格言说,代码是一种负担,所以尽可能少地使用代码。在Ruby中,代码行的区别是cero。因此,您可以使用任何一种方式(如果您不需要保存状态) 如果你想成为一个纯粹主义者,那么就使用一个模块,因为你不会使用状态功能 作为琐事信息:在Ruby中,类是一种模块
以下方法也适用
Matrix = Object.new
def Matrix.add ...
def Matrix.equals ...
那是因为所谓的“类方法”只是添加到单个对象中的方法,对象类是什么并不重要。模块和类之间的主要区别在于不能实例化模块;不能执行
obj=MyModule.new
。假设您不想实例化任何东西,所以我建议只使用模块
但是,您应该重新考虑您的方法:与其使用数组数组或其他任何表示矩阵的方法,不如创建自己的类来表示矩阵,或者。作为一种形式,模块更为正确。您仍然可以创建类的实例,即使它只有类方法。您可以在这里,将模块视为C#或Java的静态类。类还始终具有与实例相关的方法(
new
,allocate
,等等)。使用模块。类方法通常与对象有关(创建、操作对象).在您的两个示例中,您实际上并不是在类
或模块
中定义方法;您是在一个对象上定义单例方法,该对象恰好是类
或模块
,但可以是任何对象。下面是一个带有字符串的示例:
Diff = "Use me to access really cool methods"
def Diff.patch
# ...
end
您可以执行这些操作中的任何一种,但将相关方法分组的最佳方法是在模块中作为普通实例方法(即不使用self.
):
现在您可以:
- 从任何类(使用
包含差异)或任何对象(使用扩展差异)中使用此功能
- 这种用法的一个例子是
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
@alexloh我改变了答案谢谢。我将使用模块,因为这似乎是酷酷的孩子们所做的。是的,你是对的,我没有使用类或mixin,我只是想要一些类似于Java的包。我将使用模块,因为酷酷的孩子们似乎是这样做的。不过我不需要mixin功能。顺便说一句,不会“扩展自我”干扰包含?它应该让你包含它的任何类也“扩展自我”,这很可能不是有意的。@alexloh:不会的。答案修改了。
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
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