从超类初始化子类的类实例变量

时间:2014-10-03 04:19:41

标签: ruby eigenclass

鉴于下面代码中的超类,我希望所有子类都有一些实例变量。

下面的代码可以做到这一点,但无法为所有可能的子类正确初始化该变量。

我打开了我的超类的本征类。这是代码(也在rubyfiddle中):

class SomeSuperClass
  class << self
    attr_accessor :variable
    @variable = ': )' # This does't seem to have any effect
  end
  self.variable = 'This only works for the superclass'
end

class SubClass < SomeSuperClass; end

puts SomeSuperClass.variable # => 'This only works for the superclass'
puts SubClass.variable # => ''

SomeSuperClass.variable = 'I am the superclass'
SubClass.variable = 'I am the subclass'

puts SomeSuperClass.variable # => 'I am the superclass'
puts SubClass.variable # => 'I am the subclass'

我想初始化所有可能的sublcasses。在前两次放置中,仅初始化SomeSuperClass.variable。我不知道如何为所有可能的子类初始化此变量。有什么想法吗?

我找到的最佳解决方案是延迟初始化变量,覆盖访问器,如:

class SomeSuperClass
  def self.variable
    @variable ||= 'Hi'
  end
end

动机:

我需要给定类的所有子类,让我们称它为Vigilant,能够监视其直接子类上发生的一些事情。此信息存储在类中,因此每个信息具有不同的状态。

我不能使用类变量,因为两个类A&lt; B将修改相同的变量。 我也无法直接访问子类,所以我需要一种方法来为Vigilant的所有子类提供存储和检索有关其子类的信息的能力。

通过定义打开特征类的访问器,让我们说:

A.singleton_class.instance_eval { attr_accessor :x }

所有子类B class B < A; end现在都能够B.x,因为一个方法(一个访问器)被添加到它的超类特征类中,因此可以在查找中找到。

第一个例子表明B.x与A.x不同

现在,我真正不理解的是x在哪里;变量,而不是访问者。 如果我B.instance_variables它显示[],则与B.singleton_class.instance_variables相同

1 个答案:

答案 0 :(得分:2)

  

我希望所有子类在其singleton类/ eigenclass上都有一个变量。

对不起,这不是你在这里做的事情:

puts SomeSuperClass.variable # => 'This only works for the superclass'
puts SubClass.variable # => '

你为什么认为写作

SomeSuperClass.variable 

等同于伪代码:

SomeSuperClassSingletonClass.variable

或真实代码:

SomeSuperClass.singleton_class.variable

一个类和它的单例类是两个不同的类。

另外,这段代码:

  class << self
    attr_accessor :variable
    @variable = ': )' # This does't seem to have any effect   
  end

不会为该@variable创建一个访问者,与此代码相同:

class Dog
  attr_accessor :x

  @x = 'hello'
end

puts Dog.x

...不为该@x变量创建一个访问器:

--output:--
undefined method `x' for Dog:Class (NoMethodError) 

attr_accessor()的作用是:

class Dog
  def x
    @x
  end

  def x=(val)
    @x = val
  end

  #=====

  @x = 'hello'
end

这些方法与类实例变量 @x无关,它是在所有defs之外定义的。 @variables被查找(或设置)在该瞬间的任何自身对象上。可以调用那些defs的唯一对象是类Dog的实例,因此x将在Dog实例上查找(或设置) - 而不是Dog类。

另请注意,当行@x = 'hello'执行时,self等于Dog类,因此@x将自身附加到Dog类。

我认为你没有用于在单例类上设置实例变量的用例。以下是您尝试做的事情:

class SomeSuperClass
  class << self
    attr_accessor :variable
  end

  self.variable = 'hello'

  def self.inherited(subclass)
    subclass.singleton_class.instance_eval do
      attr_accessor :variable
    end

    subclass.variable = "Hi"
  end

end

class SubClass < SomeSuperClass
end

puts SomeSuperClass.variable
puts SubClass.variable


--output:--
hello
Hi

该代码创建了所谓的class instance variables。如果您认为自己有singleton class instance variables的用例,那就听听吧。