10

我有许多从一个超类继承的类。超类作为模块定义。模块内部是一个设置一些实例变量的 self.included(base) 方法。

所以是这样的:

module MyModule
  def self.included(base)
    base.instance_variable_set("@my_instance_variable", {})
  end
end

class MySuperClass
  include MyModule
end

class ClassA < MySuperClass
end

class ClassB < MySuperClass
end

除非我在 ClassA 和 ClassB 中明确包含 MyModule,否则我的实例变量将不会在这两个类中设置。

有没有办法确保在每个子类中执行模块 self.included(base) 方法而无需显式包含模块?因为它已经包含在超类中。

4

1 回答 1

16

类实例变量是类私有的。继承的类不能直接访问它们。这里有几种方法。

1.定义访问器

module MyModule
  def self.included(base)
    base.instance_variable_set :@my_instance_variable, {}
    base.extend ClassMethods
  end

  module ClassMethods
    def my_instance_variable
      # self is ClassA here, so we need to call superclass
      superclass.instance_variable_get :@my_instance_variable # => {}
    end
  end
end

class MySuperClass
  include MyModule
end

class ClassA < MySuperClass; end

ClassA.my_instance_variable # => {}

2. 更多元程序化

但是每次从你那里继承一个类时都会调用一个钩子。此时您可以设置变量。看一下这个。

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

  module ClassMethods
    # make it a class method. It will be called on target classes later.
    def enhance klass 
      klass.instance_variable_set("@my_instance_variable", {})
    end
  end
end

class MySuperClass
  include MyModule

  # this hook will get called on 'class ClassA < MySuperClass`
  def self.inherited klass
    # set class instance var on child class
    enhance klass
  end
end

class ClassA < MySuperClass; end

ClassA.instance_variable_get '@my_instance_variable' # => {}

注意:在这个示例中,每个继承的类都有自己的类实例 var(而基类没有)。这可能更适合您的情况,可能不是。

于 2012-04-04T12:16:07.200 回答