簡(jiǎn)介:
- 原型模式是一個(gè)創(chuàng)建型的模式。
- 通過給出一個(gè)原型對(duì)象來指明所創(chuàng)建的對(duì)象的類型,然后用復(fù)制這個(gè)原型對(duì)象的辦法創(chuàng)建出更多同類型的對(duì)象。
- 原型模式要求對(duì)象實(shí)現(xiàn)一個(gè)可以“克隆”自身的接口,這樣就可以通過復(fù)制一個(gè)實(shí)例對(duì)象本身來創(chuàng)建一個(gè)新的實(shí)例,這樣一來,通過原型實(shí)例創(chuàng)建新的對(duì)象,就不再需要關(guān)心這個(gè)實(shí)例本身的類型,只要實(shí)現(xiàn)了克隆自身的方法,就可以通過這個(gè)方法來獲取新的對(duì)象,而無須再去通過new來創(chuàng)建。
使用場(chǎng)景
- 原型模式多用于創(chuàng)建復(fù)雜的或者構(gòu)造耗時(shí)的實(shí)例,因?yàn)檫@種情況下,復(fù)制一個(gè)已經(jīng)存在的實(shí)例可使程序運(yùn)行更高效。
- 通過new產(chǎn)生的一個(gè)對(duì)象需要非常繁瑣的數(shù)據(jù)準(zhǔn)備或者權(quán)限,這時(shí)可以使用原型模式。
- 個(gè)對(duì)象需要提供給其他對(duì)象訪問,而且各個(gè)調(diào)用者可能都需要修改其值時(shí),可以考慮使用原型模式拷貝多個(gè)對(duì)象供調(diào)用者使用,即保護(hù)性拷貝。
原型模式的參與角色
- 客戶角色:客戶類提出創(chuàng)建對(duì)象的請(qǐng)求。
- 抽象原型角色:這是一個(gè)抽象角色,通常由一個(gè)java接口或抽象類實(shí)現(xiàn),具體原型都需要實(shí)現(xiàn)該接口。
- 具體原型角色:客戶端所需要的被復(fù)制的對(duì)象。
實(shí)例演示
/**
*
* @ Description:Cloneable 扮演抽象原型角色 Book 扮演具體原型角色,當(dāng)然也可以設(shè)成抽象原型角色,由其他具體對(duì)象來實(shí)現(xiàn)
* @Version: $version$
*/
public class Book implements Cloneable {
private String title;
private ArrayList<String> images = new ArrayList<String>();
@Override
protected Object clone() throws CloneNotSupportedException {
Book book = (Book) super.clone();
return book;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public ArrayList<String> getImages() {
return images;
}
public void setImages(String images) {
this.images.add(images);
}
public void showBook() {
System.out.println("----------------------Start----------------------");
System.out.println("title:" + title);
for (String img : images) {
System.out.println("image name:" + img);
}
System.out.println("----------------------End----------------------");
}
}
客戶角色
public class Client {
public static void main(String[] args) {
// 1.構(gòu)建書本對(duì)象
Book book1 = new Book();
// 2.編輯書本,添加圖片
book1.setTitle("書1");
book1.addImage("圖1");
book1.showBook();
// 以原型文檔為原型,拷貝一份副本
Book book2 = (Book) book1.clone();
book2.showBook();
// 修改圖書副本,不會(huì)影響原始書本
book2.setTitle("書2");
book2.showBook();
// 再次打印原始書本
book1.showBook();
}
}
輸出
----------------------Start----------------------
title:書1
image name:圖1
----------------------End----------------------
----------------------Start----------------------
title:書1
image name:圖1
----------------------End----------------------
----------------------Start----------------------
title:書2
image name:圖1
----------------------End----------------------
----------------------Start----------------------
title:書1
image name:圖1
----------------------End----------------------
備注:
book2是book的一份拷貝,它和book1的內(nèi)容是一樣的。而book2修改了“標(biāo)題”-字符串(基本的數(shù)據(jù)類型),并不影響book1的標(biāo)題,這就保證了book1的安全性。
淺拷貝引用
public class Client {
public static void main(String[] args) {
// 1.構(gòu)建書本對(duì)象
Book book1 = new Book();
// 2.編輯書本,添加圖片
book1.setTitle("書1");
book1.addImage("圖1");
book1.showBook();
// 以原型文檔為原型,拷貝一份副本
Book book2 = (Book) book1.clone();
book2.showBook();
// 修改圖書副本,不會(huì)影響原始書本
book2.setTitle("書2");
book2.addImage("圖2");
book2.showBook();
// 再次打印原始書本
book1.showBook();
}
}
輸出
----------------------Start----------------------
title:書1
image name:圖1
----------------------End----------------------
----------------------Start----------------------
title:書1
image name:圖1
----------------------End----------------------
----------------------Start----------------------
title:書2
image name:圖1
image name:圖2
----------------------End----------------------
----------------------Start----------------------
title:書1
image name:圖1
image name:圖2
----------------------End----------------------
備注
最后兩個(gè)書本內(nèi)容輸出是一致的。引用類型的新對(duì)象book2的image只是單純指向了this.image引用,并沒有重新構(gòu)造一個(gè)image對(duì)象,然后將原始書本的圖片添加到新的image對(duì)象中,這樣導(dǎo)致book2中的image與原始書本中的是同一個(gè)對(duì)象。因此,修改其中一個(gè)書本的圖片,另一個(gè)書本也會(huì)受到影響。
如何解決?因?yàn)镺bject類的clone方法只會(huì)拷貝對(duì)象中的基本的數(shù)據(jù)類型,對(duì)于數(shù)組、集合、容器對(duì)象、引用對(duì)象等都不會(huì)拷貝;所以采用深拷貝。
深拷貝應(yīng)用
/**
* 重寫拷貝方法
*/
@Override
protected Book clone() {
try {
Book book = (Book) super.clone();
// 對(duì)image對(duì)象也調(diào)用clone()函數(shù),進(jìn)行拷貝
book.image = (ArrayList<String>) this.image.clone();
return book;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
輸出
----------------------Start----------------------
title:書1
image name:圖1
----------------------End----------------------
----------------------Start----------------------
title:書1
image name:圖1
----------------------End----------------------
----------------------Start----------------------
title:書2
image name:圖1
image name:圖2
----------------------End----------------------
----------------------Start----------------------
title:書1
image name:圖1
----------------------End----------------------
備注
將book.image指向this.image的一份拷貝,而不是this.image本身,實(shí)現(xiàn)了完全的拷貝,這樣再互不影響。