Eine Klassenvariable stellt einen Zugang zu einem bestimmten Objekt dar, das allen Instanzen der Klasse und ihren Unterklassen gemein ist. Wenn man diese (von Smalltalk übernommene) Eigenschaft außer Acht lässt, gerät man schnell in Verwirrung, wie das folgende Beispiel aus der Ruby-Mailingliste zeigt.
class Fahrzeug
@@reifen = 0
def reifen
@@reifen
end
end
class Auto < Fahrzeug
@@reifen = 4
end
class Fahrrad < Fahrzeug
@@reifen = 2
end
puts Auto.new.reifen #-> 2 ??? Warum ???
Eine Klassenvariable ist innerhalb ihrer definierenden Klasse und deren Unterklassen global, so dass in obigem Beispiel also genau einer Variablen nacheinander drei Werte zugewiesen worden sind.
Um dieses Problem zu lösen, gibt es verschiedene Wege: Wenn sich der gespeicherte Wert nicht ändert, kann man eine klassenspezifische Konstante verwenden:
class Fahrzeug def reifen; type::REIFEN; end end class Auto < Fahrzeug; REIFEN = 4; end class Fahrrad < Fahrzeug; REIFEN = 2; end puts Auto.new.reifen #-> 4
Möchte man klassenspezifische Werte speichern, die sich ändern können, bieten sich Klasseninstanzvariablen an: Ebenso wie jedes Objekt seine eigenen Instanzvariablen hat, so hat jede Klasse (Instanz der Klasse Class) ihre eigenen Klasseninstanzvariablen, die nicht mit anderen Klassen geteilt werden.
class Fahrzeug
@reifen = 0
def Fahrzeug.reifen # Klassenmethode
@reifen
end
def Fahrzeug.reifen=(zahl)
@reifen = zahl
end
end
class Auto < Fahrzeug; @reifen = 4; end
class Fahrrad < Fahrzeug; @reifen = 2; end
puts Auto.new.reifen #-> 4
puts Fahrrad.new.reifen #-> 2
Eine von Guy Decoux vorgeschlagene
Lösung ist ein sehr gutes Beispiel für Ruby-typische
Programmiertechniken. Sie erlaubt es, die oben manuell
definierten Methoden kompakt als "`normale"' Akzessoren
zu beschreiben:
class Fahrzeug @reifen = 0 class << self; attr_accessor :reifen; end end class Auto < Fahrzeug; @reifen = 4; end class Fahrrad < Fahrzeug; @reifen = 2; end puts Auto.reifen, Fahrrad.reifen #-> 4 2
Hier werden innerhalb der Klassendefinition Singleton-Methoden
für die Fahrzeugklasse erzeugt, die auf die jeweils
lokal gespeicherte Klasseninstanzvariable zugreifen.