2012-11-03 10 views
6

Ich entwickle eine Klassenbibliothek.Implementieren von clone() für unveränderliche Klassen

  1. Ich habe eine abstrakte Basisklasse Matrix für Matrizen, die Implementierungen für einige der grundlegenden Methoden bietet.
  2. Abgeleitet von Matrix sind konkrete Unterklassen für verschiedene Arten von Matrizen.
  3. Ich habe die Anforderung für Matrizen klonbar sein, so implementiert Matrix die Cloneable-Schnittstelle.
  4. Einige der von Matrix abgeleiteten Klassen sind unveränderlich

wäre es für die unveränderlichen Klassen Klon Methoden akzeptabel sein, dass stattdessen ein Klon des Objekts zurückzugeben, das Objekt selbst zurückgegeben wird?

Einige (stark vereinfacht) Code zur Klarstellung:

abstract class Matrix implements Cloneable { 
    ... 
} 

class ImmutableMatrix extends Matrix { 
    ImmutableMatrix clone() { 
     return this; 
    } 
    ... 
} 

class SomeOtherMatrix extends Matrix { 
    SomeOtherMatrix clone() { 
     SomeOtherMatrix other = super.clone(); 
     ... 
     return other; 
    } 
    ... 
} 
+0

Warum überhaupt erlauben, dass Ihre Objekte geklont werden? –

+1

Einige Operationen (wie Transposition) können einfach implementiert werden, indem ein kleiner Wrapper um die ursprüngliche Matrix zurückgegeben und Werte im laufenden Betrieb berechnet werden. Außerdem können Sie den Speicherbedarf in einigen Situationen reduzieren (d. H. Operationen in großen dünn besetzten Matrizen). Dies funktioniert problemlos, solange die ursprüngliche Matrix unveränderlich ist. Andernfalls würden Änderungen an der ursprünglichen Matrix Nebenwirkungen auf das Ergebnis haben. Aber ich habe es jetzt gelöst, indem ich eine getImmutable() -Methode bereitgestellt habe, die für unveränderliche Unterklassen nur das Objekt selbst zurückgibt, während veränderbare Unterklassen eine unveränderliche Kopie zurückgeben. Kein Klonen mehr. – Axel

Antwort

8

ich super.clone() ausreichend wäre Aufruf gedacht hätte.

Wenn Ihre Klasse unveränderlich ist, sollte sie bereits alle änderbaren Klassen geklont haben, als sie erstellt wurde. Daher würde ich denken, es wäre sicher, flache Kopien von allen Feldern Ihrer Klasse zu haben.

Der JavaDocs-Status x.clone() != x wird bevorzugt. Obwohl dies keine absolute Anforderung ist, würde es sicherlich durch Ihren Plan verletzt werden, einfach this zurückzugeben.

-1

Ja Wenn wir das Verhalten von String (Unveränderbare Klasse) sehen, Wenn der Inhalt identisch ist, wird das gleiche Objekt zurückgegeben, also habe ich recht, die clone() Methode sollte nur das zurückgeben.

+1

String ist jedoch nicht zu klonen. – Axel

+0

Ja Zeichenkette kann nicht geklont werden, aber um Speicher zu sparen, wenn Inhalt von zwei Objekten gleich und unveränderlich ist, der dasselbe Objekt zurückgeben sollte, anstatt andere Objekte zu erstellen – zaffargachal

+1

Das habe ich mir auch gedacht. Endlich griff ich auf etwas anderes zurück. Die Anforderung, Cloneable mit Matrix zu implementieren, bestand darin, dass einige Methoden eine unveränderbare Kopie der als Argument übergebenen Matrix erstellen mussten. Also habe ich das Matrixargument innerhalb dieser Methoden geklont. Jetzt habe ich der Matrix-Klasse eine abstrakte 'getImmutable()' -Methode hinzugefügt und diese stattdessen verwendet. Dies erspart mir das Erstellen unnötiger Klone für unveränderliche Klassen, während die veränderbaren Klassen ihre eigene Implementierung dieser Methode bereitstellen können, indem sie eine unveränderliche Kopie der Matrix erstellen. – Axel

4

Geben Sie einfach this in der clone() - Implementierung der unveränderlichen Klassen zurück.

2

Während Sie die unveränderliche Klassen haben könnten einfach clone implementieren Verweise auf sich selbst zurück, ich bei der Verwendung clone auf die Dinge viel Wert nicht wirklich sehen, die nicht wandelbar sein kann oder nicht, abwesend unveränderlich gewisse Art und Weise der Herstellung wandelbar wird in von Dinge und umgekehrt.

Ich würde denken, dass es für Ihre Basis Matrix Klasse besser wäre, Methoden umfassen IsImmutable und IsWritable, zusammen mit AsImmutable, AsMutable und AsNewMutable Methoden; Es sollte auch Methoden zum Lesen und Schreiben der Matrix enthalten (obwohl das Aufrufen der "Write" -Methode auf einer nicht beschreibbaren Matrix eine Ausnahme auslösen sollte).

definieren statische Methoden CreateImmutableMatrix und CreateMutableMatrix die gegeben, ein Matrix, wird eine neue unveränderliche oder veränderliche Matrix erzeugen, die mit den richtigen Daten vorinitialisiert ist.

Mutable Klassen sollten AsImmutable implementieren selbst passieren zu CreateImmutableMatrix, AsMutable selbst zurückzukehren und AsNewMutable sich CreateMutableMatrix passieren.

Unveränderliche Klassen sollten implementieren AsImmutable selbst zurückzukehren, AsMutableAsNewMutable zu nennen, und AsNewMutable sich CreateMutableMatrix passieren.

Read-only-Wrapper sollte AsImmutable implementieren AsImmutable auf den gewickelten Objekte zu nennen, und AsMutable und AsNewMutableAsNewMutable auf den gewickelten Objekte zu nennen.

Ein Objekt, das eine Matrix empfängt, die es zu kopieren oder zu mutieren braucht, kann es einfach in einem Feld speichern (z. B. Foo). Wenn es die Matrix mutieren muss, kann es Foo durch Foo.AsMutable() ersetzen. Wenn das Objekt, das die Matrix enthält, kopiert werden muss, sollte das Feld in der Kopie entweder durch Foo.AsImmutable() oder Foo.AsNewMutable() ersetzt werden, je nachdem, ob das Feld in der Kopie wahrscheinlich mutiert werden muss.

+0

Vielen Dank für Ihre Antwort. Das beschreibt ziemlich gut die Lösung, die ich in der Zwischenzeit implementiert habe. – Axel

+0

@supercat Ich implementiere ein ähnliches Schema für Immutable/Mutable-Klassen mit einer Eltern-View-Schnittstelle (Ich habe auch diesen Beitrag gesehen: http://programmers.stackexchange.com/questions/221762/why-doesnt-java-8-include- unveränderbare Sammlungen). Ich sehe den Zweck der Methoden 'AsNewMutable' und' AsImmutable', aber ich bin mir nicht sicher über 'AsMutable.' Würde eine solche Methode nicht auf ein veränderbares Objekt zugreifen, würde dies bedeuten, dass Sie dieses Objekt trotzdem als änderbare Version übergeben haben sollten ? Wenn Sie diese Methode auf ein Objekt anwenden, bedeutet dies, dass Sie möglicherweise Nebenwirkungen haben oder nicht. –

+1

@AlexanderKaratarakis: Die Idee wäre, dass man "AsMutable" auf Referenzen, die garantiert (1) entweder unveränderlich sein würde, oder (2) die einzige Referenz im Universum auf das mutable Objekt in Frage - am wahrscheinlichsten Das wurde erzeugt, indem "AsMutable" auf einem unveränderlichen Objekt aufgerufen wurde und seither nicht geteilt wurde.Das Aufrufen von 'AsNewMutable' für die einzige Referenz des Universums auf ein veränderbares Objekt würde funktionieren, aber es wäre unnötig langsam. Wenn Code ein Objekt mit z.B. zehn "teure" Eigenschaften, und es ist wahrscheinlich, dass nur ein oder zwei geändert werden müssen, bevor ... – supercat

0

Ihre Klasse ist nicht streng unveränderlich, da sie nicht endgültig ist: Es kann veränderbare Unterklassen geben.

Wenn jemand will, ImmutableMatrix Unterklasse, wird er nicht in der Lage sein clone() zu implementieren, indem super.clone() Aufruf, wenn Sie nur this zurück. Also in diesem Fall sollten Sie super.clone() anrufen.

Wenn Sie jedoch Ihre Klasse endgültig machen, sehe ich keinen Grund, warum nicht einfach this zurückgeben.

+0

Wenn der Vertrag für die Klasse besagt, dass sich kein Aspekt des Zustands, der beobachtet wurde, jemals ändert, wird jede Unterklasse, die dies verletzt, gebrochen. Auch wenn es fast unmöglich ist, dass * alle * vererbbaren Klassen garantieren, dass Unterklassen ihren Vertrag einhalten, ist es gängige Praxis, in nicht sicherheitsrelevanten Kontexten davon auszugehen, dass abgeleitete Klassen dies tun. Wäre das nicht üblich, wäre Vererbung ziemlich nutzlos. Ich sehe keinen Grund, die Unveränderlichkeit als fundamental anders zu betrachten als irgendeine andere vertragliche Zusage in dieser Hinsicht. – supercat

+0

@supercat selbst wenn die Unterklasse unveränderlich ist, kann sie clone durch Aufruf von super.clone() implementieren – WilQu

+0

Wenn die Unterklasse unveränderlich ist, selbst wenn nicht alle Ableitungen der Basisklasse sind, könnte sie 'clone' durch einfaches Ausführen von' return implementieren das; '. Wenn die Klasse * durch den Vertrag * als unveränderlich festgelegt ist, kann die Implementierung von 'clone' als' return this' auch dann akzeptabel sein, wenn die Klasse vererbbar ist, vorausgesetzt, der Vertrag * dokumentiert *, dass abgeleitete Klassen berechtigterweise nichts tun, was klonen würde eindeutig sein. – supercat

Verwandte Themen