有没有办法为类方法和实例方法使用相同的代码?

时间:2013-12-20 16:59:14

标签: ruby

有没有办法为Class方法和实例方法使用相同的代码?

例如,我想做以下事情:

Module MyModule

  def method_in_module
    puts "hello"
  end

  class SomeClass       
    def some_method
      method_in_module
    end
  end
end

然后我希望能够做到这一点:

SomeClass.method_in_module

或者

a = SomeClass.new
a.method_in_module

我想我可以有两个方法,self.class_method_in_moduleinstance_method_in_module,然后将它们包含在类中(在我的实际示例类中),但代码是相同的。

2 个答案:

答案 0 :(得分:3)

您可以使用Module.included挂钩来扩展带有模块的类。

module MyModule
  def self.included(base)
    base.extend MyModule
  end

  def method_in_module
    puts "foo"
  end
end

class SomeClass
  include MyModule
end

SomeClass.new.method_in_module
# => foo
SomeClass.method_in_module
# => foo

重要的是要记住,类和实例具有不同的范围。因此,在类范围内运行良好的方法在类范围内可能效果不佳。

理想情况下,我建议在类级别定义方法,并从实例级别调用类级别方法。

一般来说,我没有看到在类级别和实例级别创建相同方法的模式在哪里是有意义的。它偶尔会有意义,但避免产生大量重复的方法。

答案 1 :(得分:0)

有多种方法可以实现这一点。一种方法是将类拉出模块,然后将/ extend模块包含到类

module MyModule
  def method_in_module
    puts "hello"
  end
end

class SomeClass
  include MyModule # adds the methods to class instances
  extend MyModule # Adds the methods to the class
end

或者,您也可以使用Ruby中的Forwardable模块,它允许您将方法转发给其他对象。

require 'forwardable'

module MyModule
  def self.method_in_module
    puts "hello"
  end

  class SomeClass
    extend Forwardable

    def_delegator :MyModule, :method_in_module

    def self.method_in_module(*args, &block)
      MyModule.method_in_module(*args, &block)
    end

    def some_method
      method_in_module
    end
  end
end

如果您处于Rails上下文中(即使用ActiveSupport),您还可以使用与上述可转发变体类似的delegate方法。

请注意,这两种变体仅可用于创建实例方法。对于类方法,您仍然需要自己定义方法,如上面的Forwardable示例所示。