Devo usare clone quando si aggiunge un nuovo elemento?Quando dovrebbero clonare essere utilizzato?

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

  •  09-06-2019
  •  | 
  •  

Domanda

Vorrei implementare in Java una classe per la gestione di dati del grafico strutture.Ho un Nodo di classe, e un Bordo di classe.Il Grafico classe gestisce due tipi di elenco:una lista di nodi e un elenco di bordi.Ogni nodo deve avere un nome univoco.Come faccio a guardia di fronte a una situazione come questa:

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"); 

Credo che dovrebbero clonare i nodi e i bordi quando li si aggiunge al grafico e restituire un NodeEnvelope classe che manterrà il grafico integrità strutturale.È questo il modo giusto di fare questo o il design è rotto dall'inizio ?

È stato utile?

Soluzione

Io lavoro con il grafico di strutture in Java un sacco, e il mio consiglio sarebbe di fare qualsiasi membro dati del Nodo e Edge classe che il Grafico dipende per mantenere la sua struttura finale, senza setter.Infatti, se è possibile, vorrei fare il Nodo e il Bordo completamente immutabile, che ha molti benefici.

Così, per esempio:

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
}

Si sarebbe poi fare il controllo di univocità nell'oggetto Grafico:

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);
    }
}

Se hai bisogno di modificare un nome di un nodo, rimuovere il vecchio nodo e aggiungere uno nuovo.Questo potrebbe sembrare di lavoro extra, ma si risparmia un sacco di fatica a tenere tutto dritto.

Davvero, però, la creazione di una propria struttura di Grafo da terra è probabilmente inutile -- questo problema è solo il primo di molti di voi sono probabilmente se costruire il proprio.

Vorrei raccomandare trovare un buon open source Java graph library, e di utilizzare invece.A seconda di che cosa si sta facendo, ci sono un paio di opzioni di là fuori.Ho usato JUNG in passato, e lo consiglio come un buon punto di partenza.

Altri suggerimenti

Non mi è chiaro perché si sta aggiungendo l'ulteriore riferimento indiretto della Stringa di nomi dei nodi.Non avrebbe più senso per il vostro Bordo del costruttore firma per essere qualcosa di simile public Edge(String, Node, Node) invece di public Edge (String, String, String)?

Non so dove clone potrebbe aiutare qui.

ETA:Se il pericolo viene dall'avere il nome del nodo è cambiato dopo che il nodo è stato creato, lanciare un IllegalOperationException se il client tenta di chiamare setName() su un nodo con un nome già esistente.

A mio parere non si dovrebbe mai clonare l'elemento meno che non si dichiari esplicitamente che i dati della tua struttura che fa.

La funzionalità desiderata la maggior parte delle cose le esigenze di effettivo dell'oggetto per essere passato in una struttura dati per riferimento.

Se si desidera rendere il Node classe più sicuro, la rendono una classe interna del grafico.

Utilizzando NodeEnvelopes o edge/nodo Fabbriche suona come overdesign per me.

Vuoi esporre un metodo setName() sul Nodo?Non c'è niente nel tuo esempio suggerire che avete bisogno di questo.Se si effettua sia il Nodo e il Bordo classi immutabili, la maggior parte di integrità-violazione di scenari che si sta immaginando diventato impossibile.(Se avete bisogno di loro per essere modificabile, ma solo fino a quando si è aggiunto un Grafico, è possibile applicare questo avendo un isInGraph bandiera sul Nodo/Edge classi che è impostato su true, Grafico.Aggiungi{Nodo, Edge}, e hanno il mutator lanciare un'eccezione se dopo la chiamata di questo flag è impostato.)

Sono d'accordo con jhkiley che il passaggio di oggetti di un Nodo al Bordo del costruttore (invece di Stringhe) suona come una buona idea.

Se si desidera una più invadente approccio, si potrebbe avere un puntatore al Nodo della classe al Grafico in cui si trova, e aggiornare il Grafico se le proprietà importanti (ad esempio, il nome del Nodo mai cambiare.Ma non potevo farlo a meno che non sei sicuro che è necessario essere in grado di cambiare i nomi dei Nodi esistenti, preservando Bordo relazioni, che sembra improbabile.

Oggetto.clone() ha alcuni importanti problemi, e il suo uso è sconsigliato nella maggior parte dei casi.Si prega di vedere l'Articolo 11, dal "Efficace Java"Joshua Bloch per una risposta completa.Credo che si può tranquillamente utilizzare l'Oggetto.clone() sui tipi primitivi array, ma a parte che avete bisogno per essere giudizioso sul corretto uso e l'override di clone.Si sono probabilmente meglio la definizione di un costruttore di copia o di un factory statico metodo che esplicitamente cloni l'oggetto secondo la vostra semantica.

In aggiunta alle osservazioni da @jhkiley.blogspot.com è possibile creare una fabbrica per i Bordi e i Nodi che si rifiuta di creare oggetti con un nome che è stato già utilizzato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top