2009-04-26 5 views
6

In meinem Java-Projekt habe ich einen Vektor von verschiedenen Arten von Händlern. Diese verschiedenen Arten von Händlern sind Unterklassen der Trader-Klasse. Im Moment habe ich eine Methode, die einen Trader als Argument verwendet und ihn etwa 50 Mal im Vektor speichert. Ich habe Probleme, weil das 50-malige Speichern des gleichen Objekts nur 50 Referenzen desselben Objekts speichert. Ich muss 50 Kopien des Objekts speichern. Ich habe über die Implementierung von Clone recherchiert, aber ich möchte nicht, dass die Programmierer, die einen Trader-Typ definieren, sich darum sorgen müssen, dass ihre Klasse klonbar wird. Wie in this page gezeigt, erzeugt der implementierende Klon alle möglichen Probleme. Ich glaube nicht, dass ein Kopierkonstruktor auch funktionieren würde, denn wenn ich einen in der Trader-Klasse definieren würde, würde er den Typ des Händlers, den er kopiert, nicht kennen und einfach einen generischen Trader erstellen. Was kann ich tun?Gibt es Alternativen zur Implementierung von Clone in Java?

Edit: Ich will nicht wirklich genaue Kopien eines bestimmten Objekts erstellen. Ich versuche wirklich, dem Vektor eine bestimmte Anzahl von Tradern hinzuzufügen. Das Problem besteht darin, dass der Benutzer in einem Argument angeben muss, welche Art von Trader er hinzufügen möchte. Hier ist ein Beispiel dafür, was ich zu tun versucht: (obwohl meine Syntax völlig imaginär)

public void addTraders(*traderType*) 
{ 
    tradervect.add(new *traderType*()) 
} 

Wie kann ich so etwas wie dies in Java erreichen?

Antwort

2

nur ein abstraktes Kopiermethode hinzuzufügen. Sie können kovariante Rückgabetypen verwenden, sodass der abgeleitete Typ angegeben wird, um eine abgeleitete Instanz zurückzugeben, die wichtig sein kann oder auch nicht.

public interface Trader { 
    Trader copyTrader(); 
    ... 
} 


public final class MyTrader implements Trader { 
    MyTrader copyTrader() { 
     return new MyTrader(this); 
    } 
    ... 
} 

Manchmal werden Sie vielleicht mit einer Sammlung von abgeleiteten Typ von Trader generisch Deal wollen, dass die Rückkehr dann eine richtig getippt Sammlung klonen muss und. Dafür können Sie Generika in einer idiomatischen Weise verwenden:

public interface Trader<THIS extends Trader> { 
    THIS copyTrader(); 
    ... 
} 


public final class MyTrader implements Trader<MyTrader> { 
    public MyTrader copyTrader() { 
     return new MyTrader(this); 
    } 
    ... 
} 
+0

Ich sehe nicht, wie ich die generische Trader-Klasse zu einer Schnittstelle machen kann, weil die Trader-Klasse über Methoden verfügt, auf die zugegriffen werden muss. Das Erstellen einer Schnittstelle würde bedeuten, dass all diese Methoden der unteren Ebene es nicht zulassen würden, dass diese Methoden in der Trader-Klasse definiert werden. –

+0

Ob Trader eine abstrakte Klasse oder Schnittstelle ist, ist irrelevant. Im Allgemeinen wird eine Schnittstelle gegenüber einer abstrakten Klasse bevorzugt. Ziehen Sie auch die Delegation zur Vererbung vor. –

0

Eine Option: Wenn Sie die Objekte serialisierbar machen können, können Sie sie serialisieren und dann deserialisieren, um eine Kopie zu erstellen, ähnlich wie beim Übergeben eines Objekts über RMI.

Schnellkopiermethode:

public MyObject copy() { 
    ObjectOutputStream oos = null; 
    ObjectInputStream ois = null; 
    try { 
     ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
     oos = new ObjectOutputStream(bos); 
     oos.writeObject(this); 
     oos.flush(); 
     ByteArrayInputStream bin = 
      new ByteArrayInputStream(bos.toByteArray()); 
     ois = new ObjectInputStream(bin); 
     return (MyObject)ois.readObject(); 
    } catch(Exception e) { 
     return null; 
    } finally { 
     try { 
      oos.close(); 
      ois.close(); 
     } catch (Exception e) { 
      return null; 
     } 
    } 
} 
+0

Warum der Downvote? Es ist eine adäquate Möglichkeit, ein komplexes Objekt zu kombinieren. Die Ressourcenverwaltung ist jedoch vollständig und vollständig unterbrochen. –

+0

Ist das die einzige Lösung? Ich kann mich nicht dazu bringen zu glauben, dass eine so einfache Operation so viel Aufhebens machen würde. Was wäre, wenn ich Clone implementieren würde, um das Kopieren zu ermöglichen? Wäre das überhaupt möglich? –

+0

@Tom: Nicht sicher, aber die Verwendung von Serialisierung/Deserialisierung für das Klonen ist ungefähr so ​​subtil wie die Verwendung von memcpy anstelle von Kopierkonstruktoren in C++. – Uri

-2

Eine Möglichkeit ist es eine endgültige Klasse wie Java eigenes String zu machen, das jede Änderung an ein Objekt der Klasse Trader machen wird eine neue Kopie im Speicher zu erstellen , aber es wird es unmöglich machen, es zu unterklassifizieren.

Ein anderer (besserer) Weg ist die Verwendung einer Factory-Methode zum Erstellen und Kopieren von Trader-Objekten, was bedeutet, dass Sie nicht zulassen dürfen, dass der Standardkonstruktor verwendet wird, d. H. Auf diese Weise können Sie die Anzahl der Instanzen der Klasse steuern. Siehe http://en.wikipedia.org/wiki/Factory_method

public class Trader { 

    /* prevent constructor so new cant be used outside the factory method */ 
    private Trader() { 
    } 

    /* the factory method */ 
    public static Trader createTrader(int whatKindOfTrader) { 

     switch (whatKindOfTrader) { 
     case 0: 
      return new Trader1(); // extends Trader 
     case 1: 
     default: 
      return new Trader2(); // extends Trader 
     } 
     return new Trader3(); // or throw exception 
    } 
} 

Sie noch eine andere überladene Methode, oder ein zweites Argument angeben könnte, die ein Trader und kopiert sie in einen neuen Klon, und ersetzt damit nimmt. BTW, möchten Sie möglicherweise die clone() -Methode überschreiben und CloneNotSupportedException auslösen, um das standardmäßige Klonen von Objekten zu verhindern.

+0

Sie meinen unveränderlich und nicht nur eine letzte Klasse. Unveränderbarkeit geht wahrscheinlich ein bisschen für ein "Händler" -Objekt. –

+0

Ich war nicht unveränderlich, aber endgültig. Es gibt einen Unterschied, und persönlich würde ich es nie benutzen. Aber die Factory-Methode ist eine Best Practice, und es ist ein gemeinsames Design-Muster Btw, unveränderliche Objekt ist einfach nicht nützlich in diesem Fall. – Azder

2

Ich bin ein wenig unklar, warum Sie 50 oder so Klone des gleichen Objekts speichern möchten, es sei denn sie der ursprüngliche Händler dient als Prototyp (siehe Muster) für spätere Händler.

Wenn Sie eine exakte Kopie eines Objekts erstellen möchten, müssen Sie das Problem der Polymorphie berücksichtigen. Wenn Personen, die Ihre Klasse unterklassifizieren, Statusmitglieder hinzufügen dürfen, haben Sie bereits genug Kopfschmerzen mit Funktionen wie equals und compareTo. Dieser Klon ist nur ein weiterer Fall, in dem Sie eine spezielle Behandlung benötigen.

Ich stimme nicht zu, dass Klon immer böse ist, ist es manchmal notwendig. In Situationen der Unterklassenbildung werden jedoch viele Dinge schwierig.

Ich würde Ihnen empfehlen zu lesen (wenn Sie die Chance haben) Blochs "Effektives Java", das viele seiner Themen behandelt. Bracha ist der Ansicht, dass es keine gute Idee ist, andere Ihre Klassen erweitern zu lassen, und wenn Sie dies tun, müssen Sie sehr gut dokumentieren, was sie tun müssten, und hoffen, dass sie Ihren Anweisungen folgen. Es gibt wirklich keine Möglichkeit, das zu umgehen. Sie können auch Ihre Händler unveränderlich machen.

Gehen Sie weiter ein Werkzeug Klonen Sie normalerweise, und zeigen Sie sehr deutlich in der Klassenkopfzeile, dass jeder, der von Ihrem Trader erbt und Staatsmitglieder hinzufügt, X-Methoden implementieren muss (was angeben).

Tricks zu finden, um einen tatsächlichen Cloneable und immer noch Clone zu umgehen, wird das Problem der Vererbung nicht überwinden. Hier gibt es keine Silberkugel.

+0

Ihre Antwort brachte mich zum Nachdenken. Siehe die Bearbeitung, die ich für weitere Informationen vorgenommen habe.:) –

+0

Warte, sagst du im Wesentlichen, wenn X Trader erweitert, und jemand eine Instanz von X an deine Funktion übergeben hat, willst du ein neues X bekommen? – Uri

+0

Wenn Sie dieses Verhalten möchten, verwenden Sie die (schrecklich) getClass.newInstance Idiom. traderType.getClass() newInstance() Sie müssen sicherstellen, dass es immer einen öffentlichen Konstruktor, und Sie wollen wahrscheinlich einige init Methode können Sie immer anrufen, um es in einen legitimen Zustand zu bringen. – Uri

0

Uri ist richtig, Polymorphie mit Staat eröffnet eine große Dose Würmer.

Ich denke, Unterklasse Cloneable und Override Clone() ist wahrscheinlich der einfachste Weg zu gehen. Sie können, glaube ich, den Rückgabetyp kovariant machen.

Verwandte Themen