Ist es möglich, Kopierkonstruktoren für Klassen mit Interface-Member-Variablen in Java zu schreiben?

8

Wie würden Sie einen Kopierkonstruktor für eine Klasse mit Interface-Member-Variablen schreiben?

Zum Beispiel:

%Vor%

Muss ich eine konkrete Animal haben? Wenn ja, scheint es, als würde die Klasse für Häuser mit Hunden vs. Häuser mit Katzen wieder verworren!

    
chessofnerd 12.06.2013, 21:24
quelle

4 Antworten

6

Sie haben eine von drei Möglichkeiten:

  1. Verfügen Sie über eine Methode auf IAnimal , um das Objekt tief zu klonen (wird von Bibliotheken wie den DOM-Schnittstellen verwendet, z. B. Node.cloneNode(boolean) )
  2. Erstellen Sie in allen Implementierungen von IAnimal einen Kopierkonstruktor, der den konkreten Typ annimmt und dies im Schnittstellenvertrag als Voraussetzung festlegt, und verwenden Sie dann reflection, um darauf zuzugreifen
  3. Erstellen Sie eine Kopierfabrik, die jede Implementierung manuell kopiert
  4. Verwenden Sie eine Bibliothek von Drittanbietern, die Deep-Cloning für Sie implementiert, mit eigenen Contracts wie No-Args-Konstruktoren, nicht-finalen Feldern, Serializable -Klassen usw., wie die aufgeführten hier

Kopiermethode

Für # 1 machen Sie etwas wie:

%Vor%

Implementieren Sie das in Ihren konkreten Typen und rufen Sie dann diese Methode auf, um es zu kopieren:

%Vor%

Dokumentieren Sie dann die Anforderung in der Schnittstelle und sagen Sie etwas wie folgt aus:

  

Implementierungen dieser Schnittstelle müssen ein Objekt, das nicht == ist, an diese Instanz zurückgeben und müssen tief geklont werden, damit die Manipulation dieses Objekts nicht zur Manipulation des zurückgegebenen Objekts und umgekehrt führt versa.

Implementierungen müssen diesem Vertrag folgen, um mit der Schnittstelle kompatibel zu sein, aber dies wird zur Kompilierzeit nicht erzwungen.

Konstruktor kopieren

Versuchen Sie, reflektiv auf einen Kopierkonstruktor zuzugreifen, und geben Sie an, dass ein Kopierkonstruktor in allen konkreten Implementierungen in der Schnittstelle erforderlich ist, der Teil des Schnittstellenvertrags wird. Jede Implementierung würde dann so aussehen:

%Vor%

Und dann brauchen Sie nur eine einzige Methode, um jede Implementierung zu kopieren:

%Vor%

Wenn Sie dies haben, fügen Sie in der Dokumentation Ihrer Schnittstelle eine entsprechende Anweisung hinzu:

  

Implementierungen dieser Schnittstelle müssen einen Kopierkonstruktor definieren, der ein Argument des gleichen Typs oder Supertyps ihrer Klasse akzeptiert. Dieser Konstruktor muss eine tiefe Kopie des Arguments erstellen, damit die Manipulation dieses Objekts nicht zur Manipulation des zurückgegebenen Objekts führt und umgekehrt.

Auch dies wird durch die Laufzeit erzwungen. Die obige copy -Methode löst NoSuchMethodException -Fehler aus, wenn der Konstruktor nicht existiert.

Kopierwerk

Dies nimmt die IAnimal und verwendet instanceof , um zu entscheiden, an welche Methode es übergeben werden soll, wie:

%Vor%

Führen Sie dann das tiefe Kopieren in den copy -Methoden für jeden Typ manuell durch.

    
Brian 12.06.2013, 21:48
quelle
2

Wenn ich Ihr Problem verstehe, da Sie Konstruktoren in einer Schnittstelle nicht angeben können, müssten Sie eine deep-copy-Methode in Ihrer Schnittstelle deklarieren und sie in Ihren Klassen implementieren. Sie können eine Schnittstelle nicht instanziieren. Sie möchten möglicherweise auch etwas in House genau nach Ihren Bedürfnissen kopieren.

%Vor%

Das Problem ist natürlich, dass es an dir liegt, etwas falsch zu machen. Es riecht irgendwie, als würde man hier nicht wirklich eine Schnittstelle wollen, sondern eine abstrakte Klasse.

    
Brian Roach 12.06.2013 21:39
quelle
1

ok, lassen Sie mich ein Problem in diesem Code erklären. Beachten Sie, dass Sie, wenn Sie eine Schnittstelle haben, ein Verhalten definieren, nicht eine Abstraktion oder Identität eines Objekts (oder einer Kreatur) wie eines Tieres. In diesem Fall benötigen Sie eine abstrakte Klasse anstelle einer Schnittstelle. das begann gesagt. Sie können keinen Konstruktor auf einer Schnittstelle haben (siehe Warum dürfen wir keinen Konstruktor in einer Schnittstelle angeben? ), daher kann die Verwendung einer Schnittstelle auf diese Weise fehlschlagen.

In diesem Fall würde ich stattdessen eine abstrakte Klasse vorschlagen:

%Vor%     
Silencio2 12.06.2013 21:45
quelle
0

Nach meinem Wissen gibt es in Java keine direkte Entsprechung dazu.

Der "richtige" Weg ist, das Interface selbst zu implementieren Cloanable .

Und der einfachste Weg könnte sein, Reflektion zu verwenden. Ich weiß, dass es eine Bibliothek gibt, die tiefe Kopien von beliebigen Objekten behandelt, aber ich kann mich im Moment nicht an den Namen erinnern.

Related: Java: empfohlene Lösung für tiefes Klonen / Kopieren eine Instanz

    
Mene 12.06.2013 21:33
quelle