通过include添加类方法

Posted

技术标签:

【中文标题】通过include添加类方法【英文标题】:Add class methods through include 【发布时间】:2013-02-24 14:54:19 【问题描述】:

我有 Ruby 类,我想在其中包含类和实例方法。按照here 描述的模式,我目前正在使用以下内容:

class SomeObject

  include SomeObject::Ability

  def self.some_builder_method(params)
    # use some_class_method ...
  end

end

module SomeObject::Ability

  module ClassMethods

    def some_class_method(param)
      # ...
    end

  end

  def self.included(klass)
    klass.extend(ClassMethods)
  end

  def some_instance_method
    # ...
  end

end

我宁愿不制作两个单独的模块(一个被包含,另一个被扩展),因为我的模块中的所有方法在逻辑上都可以组合在一起。另一方面,这种模式 a) 要求我定义一个额外的 ClassMethods 模块,并且 b) 要求我为每个模块编写一个样板文件 self.included 方法。

有没有更好的方法来做到这一点?

编辑 1:我找到了另一种方法,但我不确定这是否比第一种更好。

module Concern

  def included(base)

    # Define instance methods.
    instance_methods.each do |m|
      defn = instance_method(m)
      base.class_eval  define_method(m, defn) 
    end

    # Define class methods.
    (self.methods - Module.methods).each do |m|
      unless m == __method__
        base.define_singleton_method(m, &method(m))
      end
    end

  end

end

module SomeModule

  extend Concern

  def self.class_m
    puts "Class"
  end

  def instance_m
    puts "Instance"
  end

end

class Allo

  include SomeModule

end


Allo.class_m          # => "Class"
Allo.new.instance_m   # => "Instance"

【问题讨论】:

关于“最佳实践”等的问题。与Code Review 相关,与 SO 无关。 这与其说是“最佳实践”,不如说是“最有效的方法”问题。我同意这可能处于灰色区域,但它非常适合恕我直言。 @WouterJ 对于 *** 来说,这是一个完全可以接受的问题,并且原型问题/问题提示了一个存在于 Rails 中并在整个 Rails 中广泛使用的模块。 【参考方案1】:

如果我理解正确,你真的只想使用ActiveSupport::Concern

module PetWorthy
  extend ActiveSupport::Concern

  included do
    validates :was_pet, inclusion: [true, 'yes']
  end

  def pet #instance method
  end

  module ClassMethods
    def find_petworthy_animal
      # ...
    end
  end
end

class Kitty
  include PetWorthy
end

Kitty.find_petworthy_animal.pet

如果您没有任何行为可以触发包含,您(希望很明显)不需要使用 included 方法,但我将其放入只是为了演示。

【讨论】:

以上是关于通过include添加类方法的主要内容,如果未能解决你的问题,请参考以下文章

iOS分类延展和子类的区别

我怎样才能访问派生类私有方法?

通过指向派生类的函数调用基本虚方法

通过使用using 子类重载父类方法

扩展方法

PHP通过反射方法调用执行类中的私有方法