ruby - 使用类与模块在 Ruby 中打包代码

标签 ruby class module mixins

假设我有一堆没有持久状态的相关函数,比如字符串差分包中的各种操作。我可以在类或模块中定义它们(使用 self),并且可以用完全相同的方式访问它们:

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

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

然后我可以执行 Diff.patch(...)。哪个“更好”(或“正确”)?

我需要将它们分组的主要原因是命名空间问题,常见的函数名称都在别处使用。

编辑:将示例从矩阵更改为差异。 Matrix 是一个糟糕的例子,因为它确实有状态,每个人都开始解释为什么最好将它们写成方法而不是回答实际问题。 :(

最佳答案

在您的两个示例中,您实际上并未在 ClassModule 中定义方法;您在恰好是 ClassModule 的对象上定义单例方法,但几乎可以是任何对象。下面是一个带有 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/

相关文章:

ruby - 无法运行 bundle install 或 rails -v Rails 3.1.2

ruby-on-rails - 我可以使用 Nokogiri 插入原始 XML 字符串吗?

c++ - 使用枚举类和运算符重载分隔 header

android-studio - 如何将桌面平台模块添加到 Android Studio 中现有的 libGDX 项目?

module - Erlang中的模块和进程之间有什么关系

ruby-on-rails - 有没有一种简单的方法可以在 Passenger 的请求周期之外运行垃圾收集?

ruby-on-rails - rails : accessing field value from model method

java - 将计数器值设置回类中的初始值

php - 在同一个文件中找不到类

authentication - Yii - 具有自己的 UserIdentity 组件的模块