定義:用原型實(shí)例指定創(chuàng)建實(shí)例的種類,并通過拷貝這些原型創(chuàng)建新的對(duì)象喉誊;
使用場(chǎng)景:
- 類初始化需要消化非常多的資源,這個(gè)資源包括數(shù)據(jù)纵顾、硬件資源等伍茄,通過原型拷貝避免這些消耗侧但;
- 通過 new 產(chǎn)生一個(gè)對(duì)象需要非常繁瑣的數(shù)據(jù)準(zhǔn)備和訪問權(quán)限時(shí)府瞄;
- 一個(gè)對(duì)象需要提供給其他對(duì)象訪問邦鲫,而且各個(gè)調(diào)用者可能都需要修改其值時(shí)低矮,可以考慮使用原型模式拷貝多個(gè)對(duì)象供調(diào)用者使用,即保護(hù)性拷貝曹仗;
注意:通過實(shí)現(xiàn)Cloneable接口的原型模式在調(diào)用clone函數(shù)構(gòu)造實(shí)例時(shí)并不一定比通過new的操作速度快榨汤,只有當(dāng)通過new構(gòu)造對(duì)象較為耗時(shí)或者說(shuō)成本較高時(shí),通過clone方法才能獲得效率上的提升怎茫。實(shí)現(xiàn)原型模式也不一定需要實(shí)現(xiàn)Cloneable接口收壕,也有其他的實(shí)現(xiàn)方式。
簡(jiǎn)單實(shí)現(xiàn):
例:創(chuàng)建一個(gè)文檔對(duì)象為WordDocument轨蛤,這個(gè)文檔中含有文字和圖片蜜宪。用戶經(jīng)過長(zhǎng)時(shí)間的內(nèi)容編輯后,將其保存后并拷貝一個(gè)副本重新進(jìn)行編輯祥山;
/**
* 文檔類型
*/
class WordDocument implements Cloneable {
private String mText;
private ArrayList<String> images = new ArrayList<>();
public WordDocument() {
System.out.println("執(zhí)行WordDocument的構(gòu)造函數(shù)");
}
public String getText() {
return mText;
}
public void setText(String text) {
mText = text;
}
public ArrayList<String> getImages() {
return images;
}
public void addImage(String img) {
this.images.add(img);
}
@Override
public WordDocument clone() {
try {
WordDocument doc = (WordDocument) super.clone();
doc.mText = this.mText;
doc.images = this.images;
return doc;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
public void showDocument() {
System.out.println("———————打印WordDocument開始-----------");
System.out.println("對(duì)象:" + super.toString());
System.out.println("文本:" + mText);
System.out.println("圖片集合:");
for (String imageName : images) {
System.out.println(imageName);
}
System.out.println("———————打印完成--------------------------");
}
}
/**
* Created by admin on 2019/2/22.
* 原型模式
*/
public class Client {
public static void main(String args[]){
//1圃验、構(gòu)建文本對(duì)象
WordDocument originDoc = new WordDocument();
//2、編輯缝呕,添加文本和圖片
originDoc.setText("這是一篇用來(lái)學(xué)習(xí)原型模式的文檔");
originDoc.addImage("假圖片1");
originDoc.addImage("假圖片2");
originDoc.showDocument();
//3澳窑、拷貝一份副本
WordDocument doc2 = originDoc.clone();
doc2.showDocument();
//4、修改文檔副本
doc2.setText("拷貝的文檔2");
doc2.showDocument();
originDoc.showDocument();
}
}
運(yùn)行結(jié)果:
執(zhí)行WordDocument的構(gòu)造函數(shù)
———————打印WordDocument開始-----------
對(duì)象:sl.com.designmodedemo.cloneabledesign.WordDocument@4554617c
文本:這是一篇用來(lái)學(xué)習(xí)原型模式的文檔
圖片集合:
假圖片1
假圖片2
———————打印完成--------------------------
———————打印WordDocument開始-----------
對(duì)象:sl.com.designmodedemo.cloneabledesign.WordDocument@74a14482
文本:這是一篇用來(lái)學(xué)習(xí)原型模式的文檔
圖片集合:
假圖片1
假圖片2
———————打印完成--------------------------
———————打印WordDocument開始-----------
對(duì)象:sl.com.designmodedemo.cloneabledesign.WordDocument@74a14482
文本:拷貝的文檔2
圖片集合:
假圖片1
假圖片2
———————打印完成--------------------------
———————打印WordDocument開始-----------
對(duì)象:sl.com.designmodedemo.cloneabledesign.WordDocument@4554617c
文本:這是一篇用來(lái)學(xué)習(xí)原型模式的文檔
圖片集合:
假圖片1
假圖片2
———————打印完成--------------------------
從結(jié)果可以看出:使用clone()生成的對(duì)象doc2和第一個(gè)對(duì)象實(shí)例不同但內(nèi)容相同供常,且doc2是不會(huì)執(zhí)行構(gòu)造方法的摊聋,當(dāng)修改了doc2的內(nèi)容的內(nèi)容時(shí)并不會(huì)修改originDoc的內(nèi)容。
淺拷貝和深拷貝
上述原型模式的實(shí)現(xiàn)實(shí)際是一個(gè)淺拷貝话侧,這種拷貝實(shí)際上并不是將原始文檔的所有字段都重新構(gòu)造了一份栗精,而是副本文檔的字段引用原始文檔的字段;
我們知道A引用B就是說(shuō)兩個(gè)對(duì)象指向同一個(gè)地址瞻鹏,當(dāng)修改A時(shí)B也會(huì)改變悲立,B修改時(shí)A也會(huì)改變。上面的例子新博,將main函數(shù)修改為如下:
public static void main(String args[]){
//1薪夕、構(gòu)建文本對(duì)象
WordDocument originDoc = new WordDocument();
//2、編輯赫悄,添加文本和圖片
originDoc.setText("這是一篇用來(lái)學(xué)習(xí)原型模式的文檔");
originDoc.addImage("假圖片1");
originDoc.addImage("假圖片2");
originDoc.showDocument();
//3原献、拷貝一份副本
WordDocument doc2 = originDoc.clone();
doc2.showDocument();
//4、修改文檔副本
doc2.setText("拷貝的文檔2");
doc2.addImage("doc2添加一張圖片");
doc2.showDocument();
originDoc.showDocument();
}
查看結(jié)果:
執(zhí)行WordDocument的構(gòu)造函數(shù)
———————打印WordDocument開始-----------
對(duì)象:sl.com.designmodedemo.cloneabledesign.WordDocument@4554617c
文本:這是一篇用來(lái)學(xué)習(xí)原型模式的文檔
圖片集合:
假圖片1
假圖片2
———————打印完成--------------------------
———————打印WordDocument開始-----------
對(duì)象:sl.com.designmodedemo.cloneabledesign.WordDocument@74a14482
文本:這是一篇用來(lái)學(xué)習(xí)原型模式的文檔
圖片集合:
假圖片1
假圖片2
———————打印完成--------------------------
———————打印WordDocument開始-----------
對(duì)象:sl.com.designmodedemo.cloneabledesign.WordDocument@74a14482
文本:拷貝的文檔2
圖片集合:
假圖片1
假圖片2
doc2添加一張圖片
———————打印完成--------------------------
———————打印WordDocument開始-----------
對(duì)象:sl.com.designmodedemo.cloneabledesign.WordDocument@4554617c
文本:這是一篇用來(lái)學(xué)習(xí)原型模式的文檔
圖片集合:
假圖片1
假圖片2
doc2添加一張圖片
———————打印完成--------------------------
可以看到最后兩個(gè)對(duì)象打印結(jié)果是一樣的埂淮,都添加了一張圖片姑隅,這是由于clone方法中只是簡(jiǎn)單的進(jìn)行淺拷貝,引用類型的新對(duì)象doc2的images只是單純的指向了this.imags的引用倔撞,而沒有重新創(chuàng)建一個(gè)images對(duì)象讲仰,現(xiàn)在采用深拷貝解決上面顯示的問題,修改clone方法如下:
@Override
public WordDocument clone() {
try {
WordDocument doc = (WordDocument) super.clone();
doc.mText = this.mText;
doc.images = (ArrayList<String>) this.images.clone();
return doc;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
運(yùn)行結(jié)果為:
執(zhí)行WordDocument的構(gòu)造函數(shù)
———————打印WordDocument開始-----------
對(duì)象:sl.com.designmodedemo.cloneabledesign.WordDocument@4554617c
文本:這是一篇用來(lái)學(xué)習(xí)原型模式的文檔
圖片集合:
假圖片1
假圖片2
———————打印完成--------------------------
———————打印WordDocument開始-----------
對(duì)象:sl.com.designmodedemo.cloneabledesign.WordDocument@74a14482
文本:這是一篇用來(lái)學(xué)習(xí)原型模式的文檔
圖片集合:
假圖片1
假圖片2
———————打印完成--------------------------
———————打印WordDocument開始-----------
對(duì)象:sl.com.designmodedemo.cloneabledesign.WordDocument@74a14482
文本:拷貝的文檔2
圖片集合:
假圖片1
假圖片2
doc2添加一張圖片
———————打印完成--------------------------
———————打印WordDocument開始-----------
對(duì)象:sl.com.designmodedemo.cloneabledesign.WordDocument@4554617c
文本:這是一篇用來(lái)學(xué)習(xí)原型模式的文檔
圖片集合:
假圖片1
假圖片2
———————打印完成--------------------------
可以看見痪蝇,現(xiàn)在再給Doc2副本添加圖片時(shí)鄙陡,就不會(huì)對(duì)原型對(duì)象進(jìn)行改變了冕房;
原型模式是非常簡(jiǎn)單的一個(gè)模式,它的核心問題就是對(duì)原始對(duì)象進(jìn)行拷貝趁矾,在這個(gè)模式的使用中需要注意一點(diǎn)的是:深耙册、淺拷貝的問題。在開發(fā)過程中毫捣,為了減少錯(cuò)誤详拙,使用時(shí)應(yīng)該盡量使用深拷貝,避免操作副本時(shí)影響原始對(duì)象的問題培漏。