Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/apache-kafka/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用类vs模块在Ruby中打包代码_Ruby_Class_Module_Mixins - Fatal编程技术网

使用类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