添加新元素時我應該使用克隆嗎?什么時候應該使用克隆?

[英]Should I use clone when adding a new element? When should clone be used?


I want to implement in Java a class for handling graph data structures. I have a Node class and an Edge class. The Graph class maintains two list: a list of nodes and a list of edges. Each node must have an unique name. How do I guard against a situation like this:

我想在Java中實現一個用於處理圖形數據結構的類。我有一個Node類和一個Edge類。 Graph類維護兩個列表:節點列表和邊緣列表。每個節點必須具有唯一的名稱。我該如何防范這種情況:

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

I believe I should clone the nodes and the edges when adding them to the graph and return a NodeEnvelope class that will maintain the graph structural integrity. Is this the right way of doing this or the design is broken from the beginning ?

我相信我應該在將它們添加到圖形時克隆節點和邊緣,並返回一個將保持圖形結構完整性的NodeEnvelope類。這是正確的做法還是設計從一開始就被打破了?

6 个解决方案

#1


4  

I work with graph structures in Java a lot, and my advice would be to make any data member of the Node and Edge class that the Graph depends on for maintaining its structure final, with no setters. In fact, if you can, I would make Node and Edge completely immutable, which has many benefits.

我在Java中使用圖形結構很多,我的建議是創建Graph所依賴的Node和Edge類的任何數據成員,以保持其結構最終,沒有setter。事實上,如果可以,我會使Node和Edge完全不可變,這有很多好處。

So, for example:

所以,例如:

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
}

You would then do your uniqueness check in the Graph object:

然后,您將在Graph對象中執行唯一性檢查:

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

If you need to modify a name of a node, remove the old node and add a new one. This might sound like extra work, but it saves a lot of effort keeping everything straight.

如果需要修改節點的名稱,請刪除舊節點並添加新節點。這可能聽起來像額外的工作,但它可以節省很多努力保持一切。

Really, though, creating your own Graph structure from the ground up is probably unnecessary -- this issue is only the first of many you are likely to run into if you build your own.

但實際上,從頭開始創建自己的Graph結構可能是不必要的 - 這個問題只是您構建自己的問題時可能遇到的第一個問題。

I would recommend finding a good open source Java graph library, and using that instead. Depending on what you are doing, there are a few options out there. I have used JUNG in the past, and would recommend it as a good starting point.

我建議找一個好的開源Java圖形庫,然后使用它。根據您的工作情況,有一些選項可供選擇。我過去曾使用過JUNG,並建議將其作為一個很好的起點。

#2


3  

It isn't clear to me why you are adding the additional indirection of the String names for the nodes. Wouldn't it make more sense for your Edge constructor's signature to be something like public Edge(String, Node, Node) instead of public Edge (String, String, String)?

我不清楚為什么要為節點添加字符串名稱的附加間接。您的Edge構造函數的簽名是否更像是公共邊緣(字符串,節點,節點)而不是公共邊緣(字符串,字符串,字符串)?

I don't know where clone would help you here.

我不知道克隆會在哪里幫助你。

ETA: If the danger comes from having the node name changed after the node is created, throw an IllegalOperationException if the client tries to call setName() on a node with an existing name.

ETA:如果危險來自於在創建節點后更改節點名稱,則如果客戶端嘗試在具有現有名稱的節點上調用setName(),則拋出IllegalOperationException。

#3


1  

In my opinion you should never clone the element unless you explicitly state that your data structure does that.

在我看來,你永遠不應該克隆元素,除非你明確聲明你的數據結構這樣做。

The desired functionality of most things needs the actual object to be passed into the data structure by-reference.

大多數事物的所需功能需要將實際對象通過引用傳遞到數據結構中。

If you want to make the Node class safer, make it an inner class of the graph.

如果要使Node類更安全,請將其設置為圖的內部類。

#4


1  

Using NodeEnvelopes or edge/node Factories sounds like overdesign to me.

使用NodeEnvelopes或邊緣/節點工廠聽起來像是過度設計給我。

Do you really want to expose a setName() method on Node at all? There's nothing in your example to suggest that you need that. If you make both your Node and Edge classes immutable, most of the integrity-violation scenarios you're envisioning become impossible. (If you need them to be mutable but only until they're added to a Graph, you could enforce this by having an isInGraph flag on your Node/Edge classes that is set to true by Graph.Add{Node, Edge}, and have your mutators throw an exception if called after this flag is set.)

你真的想在Node上暴露一個setName()方法嗎?您的示例中沒有任何內容表明您需要它。如果您使Node和Edge類都不可變,那么您想象的大多數完整性違規方案都變得不可能。 (如果您需要它們是可變的,但只有在它們被添加到Graph中之后,您可以通過在Graph.Add {Node,Edge}上設置為true的Node / Edge類上具有isInGraph標志來強制執行此操作。如果在設置此標志后調用,則讓mutators拋出異常。)

I agree with jhkiley that passing Node objects to the Edge constructor (instead of Strings) sounds like a good idea.

我同意jhkiley將Node對象傳遞給Edge構造函數(而不是Strings)聽起來是個好主意。

If you want a more intrusive approach, you could have a pointer from the Node class back to the Graph it resides in, and update the Graph if any critical properties (e.g., the name) of the Node ever change. But I wouldn't do that unless you're sure you need to be able to change the names of existing Nodes while preserving Edge relationships, which seems unlikely.

如果你想要一個更具侵入性的方法,你可以有一個從Node類返回到它所在的Graph的指針,並且如果Node的任何關鍵屬性(例如名稱)發生變化,則更新Graph。但我不會這樣做,除非你確定你需要能夠在保留Edge關系的同時更改現有節點的名稱,這似乎不太可能。

#5


1  

Object.clone() has some major problems, and its use is discouraged in most cases. Please see Item 11, from "Effective Java" by Joshua Bloch for a complete answer. I believe you can safely use Object.clone() on primitive type arrays, but apart from that you need to be judicious about properly using and overriding clone. You are probably better off defining a copy constructor or a static factory method that explicitly clones the object according to your semantics.

Object.clone()有一些主要問題,在大多數情況下不鼓勵使用它。請參閱Joshua Bloch的“Effective Java”中的第11項,以獲得完整的答案。我相信你可以安全地在原始類型數組上使用Object.clone(),但除此之外,你需要明智地正確使用和重寫克隆。您可能最好定義一個復制構造函數或靜態工廠方法,根據您的語義顯式克隆對象。

#6


0  

In addition to the comments by @jhkiley.blogspot.com, you can create a factory for Edges and Nodes that refuses to create objects with a name that was already used.

除了@ jhkiley.blogspot.com的注釋之外,您還可以為Edges和Nodes創建一個工廠,拒絕創建具有已使用名稱的對象。


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2008/09/15/729e43cc9eeba6740baddef4e778dee1.html



 
粤ICP备14056181号  © 2014-2020 ITdaan.com