Die Programmiersprache Ruby (German Edition)
end
end
Dieser Code basiert immer noch auf
new
und
initialize
, macht
new
aber privat, so dass die Anwender der Klasse
Point
sie nicht direkt aufrufen können. Stattdessen müssen sie eine der eigenen Fabrikmethoden nutzen.
7.4.3 dup, clone und initialize_copy
Eine andere Möglichkeit, neue Objekte zum Leben zu erwecken, bietet sich über die Methoden
dup
und
clone
an (siehe „3.8.8 Objekte kopieren“ ). Diese Methoden allozieren eine neue Instanz der Klasse des Objekts, für das sie aufgerufen wurden. Dann kopieren sie alle Instanzvariablen und den Zustand des Empfängerobjekts in das neu allozierte Objekt.
clone
geht bei diesem Schritt noch ein wenig weiter als
dup
– es kopiert auch die Singleton-Methoden des Empfängerobjekts und friert das kopierte Objekt ein, wenn das Original eingefroren ist.
Wenn eine Klasse eine Methode namens
initialize_copy
definiert, rufen
clone
und
dup
diese Methode für das kopierte Objekt auf, nachdem sie die Instanzvariablen aus dem Original kopiert haben. (
clone
ruft
initialize_copy
auf, bevor es das kopierte Objekt einfriert, so dass
initialize_copy
immer noch verändern darf.) Der Methode
initialize_copy
wird das ursprüngliche Objekt als Argument mitgegeben, und sie hat die Möglichkeit, jede beliebige Änderung am kopierten Objekt vorzunehmen. Sie kann allerdings keine eigene Kopie des Objekts anfertigen – der Rückgabewert von
initialize_copy
wird ignoriert. Wie
initialize
stellt Ruby sicher, dass
initialize_copy
immer privat ist.
Wenn
clone
und
dup
die Instanzvariablen vom ursprünglichen Objekt in die Kopie übertragen, kopieren sie auch Referenzen auf die Werte dieser Variablen, nicht die tatsächlichen Werte. Somit wird also eine flache Kopie durchgeführt, was auch einer der Gründe dafür ist, dass viele Klassen das Verhalten dieser Methoden ändern wollen. So sieht der Code aus, der eine Methode
initialize_copy
definiert, die eine tiefere Kopie des internen Zustands vornimmt:
class Point # Ein Punkt im n-dimensionalen Raum
def initialize(*coords) # Beliebige Anzahl von Koordinaten übernehmen
@coords = coords # Koordinaten in einem Array speichern
end
def initialize_copy(orig) # Wenn jemand dieses Point-Objekt kopiert,
@coords = @coords.dup # erzeuge auch eine Kopie des Koordinaten-Array
end
end
Diese Klasse speichert ihren internen Zustand in einem Array. Ohne eine Methode
initialize_copy
würde das kopierte Objekt bei einer Erzeugung per
clone
oder
dup
auf dasselbe Array verweisen wie das ursprüngliche Objekt. Änderungen an der Kopie würden auch den Zustand des Originals beeinflussen. Da das nicht das ist, was wir wollen, müssen wir
initialize_copy
definieren, um auch eine Kopie des Array zu erzeugen.
Manche Klassen – z. B. die, die enumerierte Typen definieren – wollen eventuell die Anzahl der möglichen Instanzen einschränken. Solche Klassen müssen ihre
new
-Methode privat machen und werden vermutlich verhindern wollen, dass Kopien erzeugt werden. Der folgende Code zeigt eine Möglichkeit, das umzusetzen:
class Season
NAMES = %w{ Spring Summer Autumn Winter } # Array mit Jahreszeitennamen
INSTANCES = [] # Array mit Season-Objekten
def initialize(n) # Der Zustand einer Season ist nur ihr
@n = n # Index in den Arrays NAMES und INSTANCES
end
def to_s # Namen einer Jahreszeit zurückgeben
NAMES[@n]
end
# Dieser Code erstellt Instanzen dieser Klasse, um die Jahreszeiten bereitzustellen,
# und definiert Konstanten, um auf diese Instanzen zu referenzieren.
# Beachten Sie, dass das nach initialize geschehen muss.
NAMES.each_with_index do |name,index|
instance = new(index) # Erzeuge eine neue Instanz
INSTANCES[index] = instance # In einem Array mit Instanzen speichern
const_set name, instance # Konstante dafür definieren
end
# Jetzt haben wir alle nötigen Instanzen erzeugt und müssen
# verhindern, dass weitere angelegt werden.
private_class_method :new,:allocate # Fabrikmethoden privat machen
private :dup, :clone # Kopiermethoden privat machen
end
Dieser Code enthält einige Metaprogrammierungstechniken, die verständlicher werden, wenn Sie Kapitel 8 gelesen haben. Entscheidend daran ist die Zeile am Ende, in der die Methoden
dup
und
clone
privat gemacht werden.
Eine andere Technik, um das Kopieren von Objekten zu verhindern, ist die Verwendung von
undef
, um die Methoden
clone
und
dup
einfach zu entfernen. Oder man redefiniert die Methoden
clone
und
dup
, so dass sie eine Exception mit einer Fehlermeldung werfen, die
Weitere Kostenlose Bücher