文檔是我們在計算機上記錄文字等一個工具,通常一份文檔有一個大標題,也有許多個副標題。文檔的複製拷貝也很常見,那麼怎麼在程序設計中運用原型模式來模擬文檔的複製呢?
首先,通過UML圖大概瞭解一下原型模式吧:
Client:客戶端類
Prototype:抽象類或接口,實現了Cloneable接口
ConcretePrototype:具體的原型類
既然需要模擬文檔複製,那麼就需要先建立一個文檔:
//Docment相當於ConcretePrototype,而Cloneable接口相當於Prototype
public class Document implements Cloneable{
//主標題
private String title;
//所有副標題
private ArrayList<String> subTitles = new ArrayList<>();
@Override
protected Document clone() throws CloneNotSupportedException {
Document mNewspaper = (Document) super.clone();
mNewspaper.title = title;
mNewspaper.subTitles = subTitles;
return mNewspaper;
}
//添加副標題
public void addSubTitle(String content) {
subTitles.add(content);
}
//設置主標題
public void setTitle(String title) {
this.title = title;
}
//文檔內容
public String getDocText() {
return title + " " + subTitles.toString();
}
}
然後需要一個客戶端來進行復制:
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Document doc = new Document();
doc.setTitle("標題");
doc.addSubTitle("副標題1");
doc.addSubTitle("副標題2");
doc.addSubTitle("副標題3");
System.out.println("原文檔:" + doc.getDocText());
Document docCloning = doc.clone();
System.out.println("複製的文檔:" + docCloning.getDocText());
}
}
結果爲:
原文檔:標題 [副標題1, 副標題2, 副標題3]
複製的文檔:標題 [副標題1, 副標題2, 副標題3]
這就是原型模式的實現,但是卻會存在下列的問題,將代碼修改一下:
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Document doc = new Document();
doc.setTitle("標題");
doc.addSubTitle("副標題1");
doc.addSubTitle("副標題2");
doc.addSubTitle("副標題3");
System.out.println("原文檔:" + doc.getDocText());
Document docCloning = doc.clone();
System.out.println("複製的文檔:" + docCloning.getDocText());
System.out.println();
//克隆的對象添加一個副標題,之後輸出克隆的和原來的DOC內容
docCloning.addSubTitle("副標題4");
System.out.println("複製的文檔:" + docCloning.getDocText());
System.out.println("原文檔:" + doc.getDocText());
}
}
結果爲:
原文檔:標題 [副標題1, 副標題2, 副標題3]
複製的文檔:標題 [副標題1, 副標題2, 副標題3]複製的文檔:標題 [副標題1, 副標題2, 副標題3, 副標題4]
原文檔:標題 [副標題1, 副標題2, 副標題3, 副標題4]
會發現原來的文檔的副標題也修改了,這就引出了克隆的知識點:淺克隆與深克隆。
上述的克隆方式即爲淺克隆,雖然克隆出了一個新的文檔,但是他們對於subTitles的引用還是指向了同一個對象。要想避免出現這種問題,則需要使用深克隆,方法也很簡單:
@Override
protected Document clone() throws CloneNotSupportedException {
Document mNewspaper = (Document) super.clone();
mNewspaper.title = title;
//將引用的字段subTitles也進行克隆
mNewspaper.subTitles = (ArrayList<String>) subTitles.clone();
return mNewspaper;
}
結果爲:
複製的文檔:標題 [副標題1, 副標題2, 副標題3, 副標題4]
原文檔:標題 [副標題1, 副標題2, 副標題3]
原型模式的應用相對簡單,只不過需要注意到什麼時候應該用淺克隆,或是深克隆。該模式適用於當需要一個相同的副本,要避免使用new來產生新對象導致資源消耗時使用。
原型模式的優缺點
- 優點
– 相對於用new產生一個對象來說,會消耗更少的資源,尤其是在循環體內。 - 缺點
-原型模式是克隆二進制流,並不會執行構造方法。