2009-05-20 8 views
7

Ich kann verstehen, warum Sie eine Klassenvariable benötigen, um Dinge wie die Gesamtzahl der Objekte, die in dieser Klasse instanziiert wurden, zu verfolgen.Haben Sie jemals eine "Klasseninstanzvariable" in Ihrem Ruby-Code verwendet?

Und ich kann verstehen, warum Sie eine Instanzvariable benötigen, um Attribute eines bestimmten Objekts in dieser Klasse zu speichern.

Aber Klasse Instanzvariablen Ich kann einfach nicht zu rechtfertigen scheinen.

Wie ich es verstehe, sind sie genau wie Klassenvariablen, außer dass sie für Unterklassen nicht sichtbar sind, wie Klassenvariablen sind.

Es scheint, dass die Verwendung dafür ziemlich begrenzt wäre. Oder liege ich falsch? Hat jemand eine gute Verwendung für Klasseninstanzvariablen in ihrem Code gefunden? Oder könnten Sie ein Beispiel geben für eine Situation, in der diese Art von Nuance wertvoll wäre?

Antwort

4

Sagen Sie bitte die Anzahl der Instanzen einer Klasse (ohne Unterklassen)

class A 
    @count = 0 
    @@count = 0 
    def self.inherited(subclass) 
    subclass.instance_eval { @count = 0 } 
    end 
    def self.num_instances 
    @count 
    end 
    def self.num_subclass_instances 
    @@count 
    end 
    def self.new 
    @count += 1 
    @@count += 1 
    super 
    end 
end 
class B < A 
end 
class C < B 
end 

A.new 
B.new 
A.new 
B.new 
B.new 
C.new 

A.num_instances #=> 2 
A.num_subclass_instances #=> 6 
B.num_instances #=> 3 
B.num_subclass_instances #=> 6 
C.num_instances #=> 1 
C.num_subclass_instances #=> 6 

Sie nicht die Klassenvariable verwenden können, zählen möchten, da diese unter allen Klassen gemeinsam genutzt werden und seine Unterklassen. Beachten Sie, dass die an @@count von B und C vorgenommenen Änderungen in A widergespiegelt werden, aber @count nicht geteilt wird.

Im Allgemeinen kann es jedoch sehr nützlich sein, um klassenspezifische Einstellungen zu speichern. _why verwendet es in Dwemthy's Array, um Anfangswerte für Instanzattribute zu spezifizieren, und es kommt sehr häufig vor, wenn Ruby Metaprogrammieren.

+0

Danke. Großes Beispiel (s).Also, im Grunde, wenn wir nur Klassenvariablen hätten, wären wir nicht in der Lage, Dinge wie diese lokalisierten Zählungen für A, B und C zu tun - wir würden mit dem Äquivalent Ihrer num_subclass_instances festhalten. Ich denke, ich verstehe es jetzt. Der einzige Teil Ihres Codes, den ich nicht verstanden habe, war: def self.inherited (Unterklasse) subclass.instance_eval {@count = 0} end. Was macht das? –

+0

Also initiierte ich A @ count in der Definition von A, aber ich musste @ count für alle Unterklassen von A auch auf 0 initialisieren, was dieser Code tut. Wenn A von "subclass" geerbt wird, öffnen wir die Unterklasse und initialisieren ihren @ count auf 0. Versuchen Sie, das zu entfernen, und NoMethodErrors wird angezeigt, wenn B und C instanziiert werden, da Ruby nicht weiß, wie man 1 zu null addiert (der Standardwert von @count wenn nicht instanziiert) – rampion

+0

Got it. Vielen Dank. By the way, ich suchte nach Dokumentation auf instance_eval und fand es für 1.87 (http://www.rubybrain.com/api/ruby-1.8.7/doc/index.html?a=M000295&name=instance_eval) aber es sieht so aus wie es von 1.90 weg ist (http://www.rubybrain.com/api/ruby-1.9.0.2/doc/index.html?a=C00000022&name=Object). –

3

Klassenvariablen werden für alle Instanzen einer Klasse gemeinsam verwendet, die alle Unterklassen enthält. Manchmal ist diese Variable in einer Hierarchie genau das, was benötigt wird, aber manchmal bevorzugen Sie möglicherweise eine andere Variable für jede Klasse. Im Gegensatz zu Klassenvariablen nehmen Klasseninstanzvariablen für jedes Klassenobjekt unterschiedliche Werte an.

http://martinfowler.com/bliki/ClassInstanceVariable.html

3

Ja, eigentlich habe ich. Dies ist nur geringfügig modifiziert und getrimmt, was ich hatte:

class Widget 
    # class instance variable pattern 
    class << self; attr_accessor :color; end 

    def show_color() 
    "This widget is #{self.class.color}" 
    end 
end 
class WidgetR < Widget 
    @color = "Russet" 
end 
class WidgetC < Widget 
    @color = "Cordovan" 
end 
class WidgetL < Widget 
    @color = "Liver" 
end 

WidgetR.new.show_color #=> "This widget is Russet" 

Aber ich bin nicht sicher, ob es wirklich notwendig, in dem Fall ist, habe ich es. Ich hätte die Methode einfach außer Kraft setzen können. Oder stellte eine Farbmethode zur Verfügung. Oder es in einer Klassenvariablen als Hash gespeichert. Oder hat sogar eine Kopie in jedem Fall behalten (ok, das ist irgendwie yech). Ich bin sicher, dass es andere Möglichkeiten gibt ...

Es gibt eine Vielzahl von Alternativen und die Syntax ist umständlich. Angesichts der Tatsache, dass ich denke, die Fälle, in denen es am natürlichsten ist zu verwenden, sind wahrscheinlich ziemlich selten.

Es könnte Ihnen helfen zu versuchen, dieses Verhalten mit Klassen- und Instanzvariablen zu reproduzieren und zu sehen, dass es schwierig zu erreichen ist (obwohl es einfach ist, wenn Sie Methoden definieren, usw.).

C.J.