如何在Ruby模块之间共享方法

3

这是我尝试过的方法:

module A
  def self.method1; "method1"; end
  def method2; "method2"; end
end

module B; include A; end

B.method1  # => error
B.method2  # => error
B::method1 # => error
B::method2 # => error

我希望避免在两个模块之间复制和粘贴等效代码。我之所以在这里使用模块而不是类,是因为我不需要每个模块的多个实例,因为它们仅仅保存常量(其他模块,在此时点)。
什么是解决这个问题的最佳方法?

如果您只需要此代码的一个实例,为什么不使用单例模式? - Devin M
主要是因为我不知道那种解决方案的优缺点。有些人甚至说它们是邪恶的,而其他人似乎认为它们还可以。你怎么看? - benekastah
当它们被正确使用时,它们可以很有帮助。但我不确定你的用例是什么,所以我不能肯定地说。 - Devin M
2个回答

9

普通的include只会给你实例方法(method2在你的代码中),如果你想共享模块级别的方法,需将其提取到单独的模块中,并使用extend扩展其他模块:

module A
  extend self     # to be able to use A.method1

  def method1
    "method1"
  end
end

module B
  extend A
end

B.method1       # => "method1"

通过使用钩子方法,也可以使用include获取模块级别的方法,但需要稍微注意一下:

module A
  def self.included(other)
    other.extend ModuleMethods    # this is where the magic happens
  end

  def instance_method
    'instance method'
  end

  module ModuleMethods
    def module_method
      'module method'
    end
  end

  extend ModuleMethods     # to be able to use A.module_method
end


module B
  include A
end

B.module_method        #=> "module method"
B.instance_methods     #=> [:instance_method]

请注意,这不会给你A.method1 - 如果你想要那个,一个选项是在A内部调用“extend self”。 - Greg Campbell

1
首先,请注意A.method2也不起作用。您可以创建包括A(或B)的对象,这些对象将具有method2
class C
  include B    # (or A)
end
c = C.new
c.method2

所以,对于method2,它按照您的意图正常工作。

关于method1,它是对象A的单例方法,无法继承。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接