Soll ich Klon verwenden, wenn ein neues Element hinzuzufügen? Wann sollte -Klon werden?

StackOverflow https://stackoverflow.com/questions/63748

  •  09-06-2019
  •  | 
  •  

Frage

Ich mag für den Umgang mit Graphendatenstrukturen in Java eine Klasse implementieren. Ich habe eine Node-Klasse und eine Edge-Klasse. Die Graph-Klasse unterhält zwei Liste: eine Liste von Knoten und eine Liste von Kanten. Jeder Knoten muss einen eindeutigen Namen haben. Wie schützen ich gegen eine Situation wie folgt aus:

Graph g = new Graph();

Node n1 = new Node("#1");
Node n2 = new Node("#2");

Edge e1 = new Edge("e#1", "#1", "#2");

// Each node is added like a reference
g.addNode(n1);
g.addNode(n2);
g.addEdge(e1);

// This will break the internal integrity of the graph
n1.setName("#3");   
g.getNode("#2").setName("#4"); 

Ich glaube, ich sollte die Knoten und die Kanten klonen, wenn sie auf den Graphen und gibt eine NodeEnvelope Klasse hinzufügen, die die Grafik strukturelle Integrität beibehalten wird. Ist dies der richtige Weg, dies zu tun oder das Design von Anfang an defekt?

War es hilfreich?

Lösung

Ich arbeite mit Graphenstrukturen in Java viel, und mein Rat wäre, alle Daten, Mitglied der Knoten und Edge-Klasse zu machen sein, dass der Graph seine Struktur endgültig für die Aufrechterhaltung abhängt, ohne Setter. In der Tat, wenn Sie können, würde ich Knoten machen und völlig unveränderlich Rand, der hat viele Vorteile .

So zum Beispiel:

public final class Node {

    private final String name;

    public Node(String name) {
           this.name = name;
    }

    public String getName() { return name; }
    // note: no setter for name
}

Sie würden dann tun Sie Ihre Einzigartigkeit Prüfung im Graph-Objekt:

public class Graph {
    Set<Node> nodes = new HashSet<Node>();
    public void addNode(Node n) {
        // note: this assumes you've properly overridden 
        // equals and hashCode in Node to make Nodes with the 
        // same name .equal() and hash to the same value.
        if(nodes.contains(n)) {
            throw new IllegalArgumentException("Already in graph: " + node);
        }
        nodes.add(n);
    }
}

Wenn Sie einen Namen eines Knotens ändern müssen, entfernen Sie den alten Knoten und fügen Sie eine neue. Dies mag wie zusätzliche Arbeit klingen, aber es spart viel Mühe halten alles gerade.

Wirklich, aber Ihre eigene Graph Struktur von Grund auf neu zu schaffen ist wahrscheinlich nicht notwendig -. Dieses Problem ist nur die erste von vielen sind Sie wahrscheinlich in ausführen, wenn Sie Ihre eigenen bauen

Ich würde empfehlen, eine gute Open-Source-Java Graph-Bibliothek zu finden, und die Verwendung dieser statt. Je nachdem, was Sie tun, es gibt da draußen ein paar Optionen. Ich habe verwendet JUNG in der Vergangenheit , und würde es als ein guter Ausgangspunkt empfehlen.

Andere Tipps

Es ist mir nicht klar, warum Sie die zusätzliche Indirektion des String-Namen für den Knoten hinzugefügt werden. Wäre es nicht sinnvoller für das Edge-Konstruktor Unterschrift macht so etwas wie public Edge(String, Node, Node) sein statt public Edge (String, String, String)?

Ich weiß nicht, wo Klon würde Ihnen dabei helfen.

ETA. Wenn die Gefahr von mit dem Namen, nachdem der Knoten geändert Knoten kommt, wird erstellt, ein IllegalOperationException werfen, wenn der Kunde setName () auf einem Knoten mit einem vorhandenen Namen zu nennen versucht

Meiner Meinung nach sollten Sie nie das Element klonen, wenn Sie ausdrücklich fest, dass Ihre Datenstruktur, dass der Fall ist.

Die gewünschte Funktionalität der meisten Dinge braucht das eigentliche Objekt in die Datenstruktur von Verweise übergeben werden.

Wenn Sie die Node Klasse sicherer machen wollen, ist es eine innere Klasse des Graphen machen.

Mit NodeEnvelopes oder Kante / Knoten Fabriken klingt wie eine Überdimensionierung zu mir.

Haben Sie wirklich eine setName () -Methode auf Knoten überhaupt verfügbar machen möchten? Es gibt nichts in Ihrem Beispiel dafür, dass Sie das brauchen. Wenn Sie sowohl Ihre Node und Edge-Klassen unveränderlich machen, die meisten der Integrität-Verletzung Szenarien sind Sie unmöglich Envisioning werden. (Wenn Sie sie benötigen wandelbar zu sein, aber nur, bis sie zu einem Diagramm hinzugefügt sind, können Sie dies erzwingen, indem sie ein isInGraph Flagge auf Ihrem Knoten / Kantenklassen aufweist, der auf true Graph.Add {Knoten, Kante} gesetzt ist, und hat Ihre Mutatoren eine Ausnahme auslösen, wenn aufgerufen, nachdem dieser Flag gesetzt ist.)

ich mit jhkiley einigen, die Node-Objekte an den Edge-Konstruktor (anstelle von Strings) wie eine gute Idee klingt.

Wenn Sie einen aufdringlichen Ansatz mögen, können Sie einen Zeiger von der Node-Klasse auf den Graph es liegt in haben zurück, und das Diagramm aktualisieren, wenn die kritischen Eigenschaften (zum Beispiel des Name) des Knotens jemals ändern. Aber ich würde das nicht tun, wenn Sie sicher sind Sie müssen in der Lage sein, die Namen zu ändern Knoten bestehenden während Edge-Beziehungen zu bewahren, die scheint unwahrscheinlich.

Object.clone () hat einige wichtige Probleme, und seine Verwendung ist in den meisten Fällen abgeraten. Bitte beachten Sie Punkt 11, von " Effective Java " von Joshua Bloch für eine vollständige Antwort . Ich glaube, Sie sicher Object.clone () auf primitive Art Arrays verwenden können, aber abgesehen davon, dass Sie richtig mit und überwiegendes Klon vernünftig sein müssen. Sie sind wahrscheinlich besser dran, einen Copy-Konstruktor oder eine statische Factory-Methode definiert, die das Objekt explizit klont nach Ihrer Semantik.

Neben den Kommentaren von @ jhkiley.blogspot.com, können Sie eine Fabrik für Kanten und Knoten erstellen, die Objekte mit einem Namen erstellen weigert, die bereits verwendet wurde.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top