介紹:
原型模式是一種創(chuàng)建型模式媳荒,用原型實(shí)例指定創(chuàng)建對象的種類,并且通過拷貝這些原型創(chuàng)建新的對象驹饺。
類圖:
Prototype(抽象原型類):抽象類或接口钳枕,聲明復(fù)制方法。
ConcretePrototype(具體原型類):具體被復(fù)制的對象赏壹。
Client(客戶端類):調(diào)用類鱼炒。
用法:
? 類初始化時(shí)候需要消耗非常多資源,通過原型拷貝避免這些消耗蝌借。
? 通過new產(chǎn)生一個(gè)對象時(shí)候需要非常繁瑣的數(shù)據(jù)準(zhǔn)備或訪問權(quán)限時(shí)昔瞧。
? 一個(gè)對象需要提供給其它對象使用,并且各個(gè)調(diào)用者都可能修改其值時(shí)菩佑,可以考慮使用自晰,即保護(hù)性拷貝。
個(gè)人理解:
? 在某個(gè)時(shí)刻從某個(gè)類的實(shí)例到一個(gè)與此時(shí)此刻相同又不相互影響的實(shí)例稍坯,實(shí)際上就是動態(tài)抽取當(dāng)前對象運(yùn)行時(shí)的狀態(tài)酬荞。
? 當(dāng)然我們并不是在任何情況下創(chuàng)建復(fù)雜對象都適合用這種模式,例如我需要初始化一個(gè)復(fù)雜且干凈的類時(shí)還是考慮使用工廠方法模式瞧哟。
例子:
原型模式的原理是對象拷貝混巧。在Java中使用clone方法復(fù)制一個(gè)對象,就是原型模式的體現(xiàn)了勤揩。日常工作中咧党,在我們編輯Word文檔的時(shí)候,為了安全起見會拷貝一份當(dāng)前文檔的狀態(tài)再進(jìn)行修改陨亡,下面我們以這個(gè)例子說明一下這個(gè)模式:
需求:實(shí)現(xiàn)文檔拷貝
1傍衡、引用拷貝
1.1深员、Word中有文字和圖片,因此創(chuàng)建一個(gè)Word文檔對象蛙埂。
public class WordDocument {
private String mText;
private ArrayList<String> mImages = new ArrayList<>();
public void setText(String text) {
this.mText = text;
}
public void addImages(String img) {
this.mImages.add(img);
}
public void show() {
System.out.println("------- Word Start ------");
System.out.println("文本內(nèi)容:" + mText);
for (String imgs : mImages) {
System.out.println("圖片名稱:" + imgs);
}
System.out.println("------- Word End ------");
}
}
1.2辨液、用引用拷貝實(shí)現(xiàn)
實(shí)現(xiàn)復(fù)制功能很多初學(xué)者第一時(shí)間可能是想到這樣寫:
public class Client {
public static void main(String[] args) {
WordDocument a = new WordDocument();
a.setText("啦啦啦");
//拷貝a對象
WordDocument b = a;
//修改b的內(nèi)容
b.setText("呵呵呵");
}
}
輸出結(jié)果卻不如人意,修改b的時(shí)候把原始的文檔a也同時(shí)修改了:
//a的原始內(nèi)容輸出:
文本內(nèi)容:啦啦啦
//修改b后輸出a:
文本內(nèi)容:呵呵呵
//修改b后輸出b:
文本內(nèi)容:呵呵呵
1.3箱残、引用拷貝概念
兩個(gè)對象的引用相同,都指向同一個(gè)對象止吁,就叫引用拷貝被辑。我們抽離出核心代碼解釋一下:
WordDocument a = new WordDocument();
WordDocument b = a;
在內(nèi)存中發(fā)生如下事情:
本質(zhì)上是復(fù)制了一個(gè)引用b,同時(shí)指向了堆區(qū)的對象敬惦。所以通過b將"啦啦啦"修改為"呵呵呵"后盼理,a的輸出結(jié)果也為"呵呵呵"了。所以我們怎么做才能從堆區(qū)中復(fù)制一個(gè)對象呢俄删?
2宏怔、對象拷貝
2.1、使用原型模式實(shí)現(xiàn)
在java中畴椰,Cloneable接口相當(dāng)于Prototype臊诊,而我們的WordDocument就相當(dāng)于ConcretePrototype了。因此我們修改下1.1中的類:
public class WordDocument implements Cloneable {
//....省略部分代碼
@Override
protected Object clone() throws CloneNotSupportedException {
try {
WordDocument doc = (WordDocument)super.clone();
doc.mText = this.mText;
doc.mImages = this.mImages;
return doc;
} catch (Exception e){
e.printStackTrace();
}
return null;
}
}
2.2斜脂、修改一下1.1中的實(shí)現(xiàn)部分:
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
WordDocument a = new WordDocument();
a.setText("啦啦啦");
a.show();
//拷貝a對象
WordDocument b = (WordDocument) a.clone();
//修改b的內(nèi)容
b.setText("呵呵呵");
}
}
輸出結(jié)果:
//a的原始內(nèi)容輸出:
文本內(nèi)容:啦啦啦
//修改b后輸出a:
文本內(nèi)容:啦啦啦
//修改b后輸出b:
文本內(nèi)容:呵呵呵
2.3抓艳、對象拷貝概念
從堆區(qū)中復(fù)制一個(gè)類型和值都是之前的一樣的對象,就叫對象拷貝帚戳。深拷貝和淺拷貝都是對象拷貝玷或。關(guān)鍵代碼如下:
WordDocument a = new WordDocument();
WordDocument b = (WordDocument) a.clone();
我們再看下內(nèi)存中是怎樣的:
通過clone()方法,堆區(qū)的"啦啦啦"復(fù)制出一個(gè)對象片任,b引用之后將它改為"呵呵呵"偏友。它們的內(nèi)存地址都是不同的。
3对供、淺拷貝與深拷貝
3.1位他、淺拷貝的實(shí)現(xiàn)
我們繼續(xù)完善我們的代碼,加入圖片部分的邏輯:
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
WordDocument a = new WordDocument();
a.setText("啦啦啦");
a.addImages("圖片1.jpg");
a.addImages("圖片2.jpg");
a.addImages("圖片3.jpg");
a.show();
WordDocument b = (WordDocument) a.clone();
//修改B的內(nèi)容
b.setText("呵呵呵");
b.addImages("呵呵.jpg");
//同時(shí)輸出
a.show();
b.show();
}
}
輸出結(jié)果:
------- Word Start ------
文本內(nèi)容:啦啦啦
圖片名稱:圖片1.jpg
圖片名稱:圖片2.jpg
圖片名稱:圖片3.jpg
------- Word End ------
------- Word Start ------
文本內(nèi)容:啦啦啦
圖片名稱:圖片1.jpg
圖片名稱:圖片2.jpg
圖片名稱:圖片3.jpg
圖片名稱:呵呵.jpg
------- Word End ------
------- Word Start ------
文本內(nèi)容:呵呵呵
圖片名稱:圖片1.jpg
圖片名稱:圖片2.jpg
圖片名稱:圖片3.jpg
圖片名稱:呵呵.jpg
------- Word End ------
我們不難發(fā)現(xiàn)犁钟,修改后圖片部分的內(nèi)容輸出竟然是一致的棱诱。我們添加了"呵呵.jpg"直接插入了原來的數(shù)組里面了。因?yàn)樵谖覀?.1中的clone()方法只是簡單的進(jìn)行淺拷貝涝动,mImages只是單純指向了this.mImages的引用迈勋,并沒有重新構(gòu)造一個(gè)mImages對象,這樣導(dǎo)致了b中的mImages與原始文檔是同一個(gè)對象了醋粟。
3.2靡菇、淺拷貝的概念
上述例子在內(nèi)存的情況如下:
在淺拷貝中僅僅克隆基本類型的變量重归,而不克隆引用類型的變量。String類型也是一種引用類型厦凤,為什么卻不受影響呢鼻吮?
String類型非常特殊,它屬于引用數(shù)據(jù)類型较鼓,不屬于基本數(shù)據(jù)類型椎木,但是String類型的數(shù)據(jù)是存放在常量池中的,也就是無法修改的博烂。
3.3香椎、深拷貝的實(shí)現(xiàn)
我們將2.1的clone方法修改,克隆方法中的對象也執(zhí)行一下clone()方法:
public class WordDocument implements Cloneable {
//省略部分代碼
@Override
protected Object clone() throws CloneNotSupportedException {
try {
WordDocument doc = (WordDocument)super.clone();
doc.mText = this.mText;
doc.mImages = (ArrayList<String>) this.mImages.clone();
return doc;
} catch (Exception e){
e.printStackTrace();
}
return null;
}
}
再執(zhí)行3.1中Client類的代碼禽篱,效果如下:
------- Word Start ------
文本內(nèi)容:啦啦啦
圖片名稱:圖片1.jpg
圖片名稱:圖片2.jpg
圖片名稱:圖片3.jpg
------- Word End ------
------- Word Start ------
文本內(nèi)容:啦啦啦
圖片名稱:圖片1.jpg
圖片名稱:圖片2.jpg
圖片名稱:圖片3.jpg
------- Word End ------
------- Word Start ------
文本內(nèi)容:呵呵呵
圖片名稱:圖片1.jpg
圖片名稱:圖片2.jpg
圖片名稱:圖片3.jpg
圖片名稱:呵呵.jpg
------- Word End ------
我們看到畜伐,加了"呵呵.jpg"之后并不影響原本的對象了。再看一下內(nèi)存:
4躺率、總結(jié)
原型模式原理就是對象拷貝玛界,而對象拷貝中分為淺拷貝和深拷貝。這個(gè)也是值得注意的問題悼吱。為了減少使用錯誤我認(rèn)為都應(yīng)該盡可能使用深拷貝慎框,避免操作副本時(shí)影響原始對象的問題。
淺拷貝:僅僅復(fù)制基本類型的變量舆绎,而不復(fù)制引用類型的變量鲤脏。
深克隆:既復(fù)制基本類型的變量吕朵,也復(fù)制引用類型變量猎醇。
感謝您的閱讀~
轉(zhuǎn)載請注明出處喔:http://www.reibang.com/p/d89b6f77a60f
推薦閱讀
基礎(chǔ)篇:
設(shè)計(jì)模式前篇之——UML類圖必會知識點(diǎn)
設(shè)計(jì)模式前篇之——一起過一下面向?qū)ο蟮母拍?/a>
創(chuàng)建型模式:
簡易理解設(shè)計(jì)模式之:簡單工廠模式——來試試接入支付功能
簡易理解設(shè)計(jì)模式之:工廠方法模式——數(shù)據(jù)存儲例子
簡易理解設(shè)計(jì)模式之:抽象工廠模式——更換數(shù)據(jù)庫例子
簡易理解設(shè)計(jì)模式之:建造者模式——學(xué)習(xí)使用“鏈?zhǔn)秸{(diào)用”
簡易理解設(shè)計(jì)模式之:原型模式——深、淺拷貝的概念
簡易理解設(shè)計(jì)模式之:單例模式——單例模式的幾種常用寫法
結(jié)構(gòu)型模式:
簡易理解設(shè)計(jì)模式之:適配器模式——Android列表視圖控件設(shè)計(jì)方式
簡易理解設(shè)計(jì)模式之:橋接模式——穿衣服經(jīng)典案例2
簡易理解設(shè)計(jì)模式之:組合模式——實(shí)現(xiàn)View中的樹狀結(jié)構(gòu)
簡易理解設(shè)計(jì)模式之:裝飾模式——穿衣服經(jīng)典案例
簡易理解設(shè)計(jì)模式之:外觀模式——第三方SDK的幫助類
簡易理解設(shè)計(jì)模式之:享元模式——五子棋游戲例子
簡易理解設(shè)計(jì)模式之:代理模式——iOS視圖控件設(shè)計(jì)方式
行為型模式:
簡易理解設(shè)計(jì)模式之:策略模式——優(yōu)化一下支付功能
簡易理解設(shè)計(jì)模式之:模板方法模式——Android中的BaseActivity基類
簡易理解設(shè)計(jì)模式之:觀察者模式——監(jiān)聽與回調(diào)
簡易理解設(shè)計(jì)模式之:狀態(tài)模式——優(yōu)化登錄操作
簡易理解設(shè)計(jì)模式之:備忘錄模式——Word文檔的工作原理
簡易理解設(shè)計(jì)模式之:迭代器模式——遍歷對象的好幫手
簡易理解設(shè)計(jì)模式之:命令模式——實(shí)現(xiàn)命令的參數(shù)化配置
簡易理解設(shè)計(jì)模式之:責(zé)任鏈模式——OA中請假流程示例
簡易理解設(shè)計(jì)模式之:中介者模式——多人聊天室例子
簡易理解設(shè)計(jì)模式之:解釋器模式——語言和文法
簡易理解設(shè)計(jì)模式之:訪問者模式——員工考核例子