简体   繁体   English

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

[英]Using Class vs Module for packaging code in Ruby

Let's say I have a bunch of related functions that have no persistent state, say various operations in a string differencing package. 假设我有一堆没有持久状态的相关函数,比如字符串差异包中的各种操作。 I can either define them in a class or module (using self ) and they can be accessed the exact same way: 我可以在类或模块中定义它们(使用self ),它们可以以完全相同的方式访问:

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

or 要么

module Diff
  def self.diff ...
  def self.patch ...
end

I can then do Diff.patch(...) . 然后我可以做Diff.patch(...) Which is 'better' (or 'correct')? 哪个'更好'(或'正确')?

The main reason I need to group them up is namespace issues, common function names are all used elsewhere. 我需要将它们分组的主要原因是命名空间问题,常用的函数名称都在其他地方使用。

Edit: Changed example from matrix to diff. 编辑:将示例从矩阵更改为差异。 Matrix is a terrible example as it does have state and everyone started explaining why it's better to write them as methods rather than answer the actual question. Matrix是一个可怕的例子,因为它确实有状态,每个人都开始解释为什么把它们作为方法而不是回答实际问题更好。 :( :(

The main difference between modules and classes is that you can not instantiate a module; 模块和类之间的主要区别在于您无法实例化模块; you can't do obj = MyModule.new . 你不能做obj = MyModule.new The assumption of your question is that you don't want to instantiate anything, so I recommend just using a module. 你的问题的假设是你不想实例化任何东西,所以我建议你只使用一个模块。

Still you should reconsider your approach: rather than using arrays of arrays or whatever you are doing to represent a Matrix, it would be more elegant to make your own class to represent a matrix, or find a good class that someone else has already written . 仍然你应该重新考虑你的方法:不是使用数组或你正在做的任何代表矩阵的数组,而是让你自己的类来表示矩阵,或找到别人已经写过的好类更优雅。

In your two examples, you are not actually defining methods in a Class or a Module ; 在您的两个示例中,您实际上并未在ClassModule定义方法; you are defining singleton methods on an object which happens to be a Class or a Module , but could be just about any object. 你是在一个恰好是ClassModule的对象上定义单例方法,但可能只是关于任何对象。 Here's an example with a String : 这是一个String的例子:

Diff = "Use me to access really cool methods"

def Diff.patch
  # ...
end

You can do any of these and that will work, but the best way to group related methods is in a Module as normal instance methods (ie without self. ): 您可以执行其中的任何操作,但这样可以将相关方法分组的最佳方法是在Module作为普通实例方法(即没有self. ):

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

Now you can: 现在你可以:

  • use this functionality from within any Class (with include Diff ) or from any object (with extend Diff ) 在任何类( include Diff )或任何对象(使用extend Diff )中使用此功能
  • an example of this use is the extend self line which makes it possible to call Diff.patch . 这种用法的一个例子是extend self line,它可以调用Diff.patch
  • even use these methods in the global namespace 甚至在全局命名空间中使用这些方法

For example, in irb : 例如,在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

Note : the extend self will "modify" the Diff module object itself but it won't have any effect on inclusions of the module. 注意extend self将“修改” Diff模块对象本身,但它不会对模块的包含产生任何影响。 Same thing happens for a def self.foo , the foo won't be available to any class including it. 对于def self.foo也会发生同样的事情, foo将无法用于包括它的任何类。 In short, only instance methods of Diff are imported with an include (or an extend ), not the singleton methods. 简而言之,只有Diff实例方法是使用include (或extend )导入的,而不是单例方法。 Only subclassing a class will provide inheritance of both instance and singleton methods. 仅对类进行子类化将提供实例和单例方法的继承。

When you actually want the inclusion of a module to provide both instance methods and singleton methods, it's not completely easy. 当你真的希望包含一个模块来提供实例方法和单例方法时,它并不容易。 You have to use the self.included hook: 你必须使用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

Ruby Modules are used to specify behaviour, pieces of related functionality. Ruby模块用于指定行为,相关功能。

Ruby Classes are used to specify both state and behaviour, a singular entity. Ruby Classes用于指定状态和行为,一个单一的实体。

There is a maxim in software design that says that code is a liability, so use the less code possible. 软件设计中有一个格言,即代码是一种负担,因此尽可能使用较少的代码。 In the case of Ruby, the difference in code lines is cero. 在Ruby的情况下,代码行的差异是cero。 So you can use either way (if you don't need to save state) 所以你可以使用任何一种方式(如果你不需要保存状态)

If you want to be a purist, then use a Module, since you won't be using the State functionality. 如果您想成为纯粹主义者,请使用模块,因为您不会使用状态功能。 But I wouldn't say that using a class is wrong. 但我不会说使用类是错误的。

As a trivia info: In Ruby a Class is a kind of Module. 作为一个琐事信息:在Ruby中,类是一种模块。

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

The following also works 以下也有效

Matrix = Object.new

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

That's because so-called "class methods" are just methods added to a single object, and it doesn't really matter what that object class is. 那是因为所谓的“类方法”只是添加到单个对象的方法,而对象类的含义并不重要。

As a matter of form, the Module is more correct. 作为形式,模块更正确。 You can still create instances of the class, even if it has only class methods. 您仍然可以创建类的实例,即使它只有类方法。 You can think of a module here as a static class of C# or Java. 您可以将此处的模块视为C#或Java的静态类。 Classes also always have the instance related methods ( new , allocate , etc.). 类也始终具有与实例相关的方法( newallocate等)。 Use the Module. 使用模块。 Class methods usually have something to do with objects (creating them, manipulating them). 类方法通常与对象有关(创建它们,操纵它们)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM