以下のコードのスーパークラスを考えると、すべてのサブクラスにいくつかのインスタンス変数が必要です。
以下のコードはそれを行いますが、考えられるすべてのサブクラスに対してその変数を適切に初期化できません。
スーパークラスの固有クラスを開きました。これがコードです(これも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'
可能なすべてのサブクラスを初期化したいと思います。最初の 2 つのプットでは、のみSomeSuperClass.variable
が初期化されます。考えられるすべてのサブクラスに対してこの変数を初期化する方法がわかりません。何か案は?
私が見つけた最善の解決策は、次のように、アクセサーをオーバーライドして変数を遅延初期化することです。
class SomeSuperClass
def self.variable
@variable ||= 'Hi'
end
end
動機:
特定のクラスのすべてのサブクラスが必要です。それを警戒と呼びましょう。直接のサブクラスで起こっていることを監視できます。この情報はクラスに保存されるため、それぞれの状態が異なります。
2 つのクラス A < B が同じ変数を変更するため、クラス変数は使用できません。サブクラスにも直接アクセスできないため、Vigilant のすべてのサブクラスに、サブクラスに関する情報を保存および取得するための容量を与える方法が必要でした。
固有クラスを開くアクセサーを定義することにより、次のように言えます。
A.singleton_class.instance_eval { attr_accessor :x }
メソッド (アクセサ) がそのスーパークラスの固有クラスに追加されたため、すべてのサブクラス Bclass B < A; end
が実行できるようになり、ルックアップで見つけることができます。B.x
最初の例は、Bx が Ax と異なることを示しています。
さて、私が本当に理解していないのは、x がどこにあるかです。アクセサーではなく、変数。私がそれを行うB.instance_variables
と[]
、 B.singleton_class.instance_variables と同じように表示されます