簡介:
- 原型模式是一個創(chuàng)建型的模式感昼。
- 通過給出一個原型對象來指明所創(chuàng)建的對象的類型澈缺,然后用復制這個原型對象的辦法創(chuàng)建出更多同類型的對象娶聘。
- 原型模式要求對象實現(xiàn)一個可以“克隆”自身的接口煮剧,這樣就可以通過復制一個實例對象本身來創(chuàng)建一個新的實例斥滤,這樣一來,通過原型實例創(chuàng)建新的對象勉盅,就不再需要關心這個實例本身的類型佑颇,只要實現(xiàn)了克隆自身的方法,就可以通過這個方法來獲取新的對象草娜,而無須再去通過new來創(chuàng)建挑胸。
使用場景
- 原型模式多用于創(chuàng)建復雜的或者構造耗時的實例,因為這種情況下宰闰,復制一個已經存在的實例可使程序運行更高效茬贵。
- 通過new產生的一個對象需要非常繁瑣的數(shù)據準備或者權限,這時可以使用原型模式移袍。
- 個對象需要提供給其他對象訪問解藻,而且各個調用者可能都需要修改其值時,可以考慮使用原型模式拷貝多個對象供調用者使用葡盗,即保護性拷貝螟左。
原型模式的參與角色
- 客戶角色:客戶類提出創(chuàng)建對象的請求。
- 抽象原型角色:這是一個抽象角色觅够,通常由一個java接口或抽象類實現(xiàn)胶背,具體原型都需要實現(xiàn)該接口。
- 具體原型角色:客戶端所需要的被復制的對象喘先。
實例演示
/**
*
* @ Description:Cloneable 扮演抽象原型角色 Book 扮演具體原型角色钳吟,當然也可以設成抽象原型角色,由其他具體對象來實現(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.構建書本對象
Book book1 = new Book();
// 2.編輯書本窘拯,添加圖片
book1.setTitle("書1");
book1.addImage("圖1");
book1.showBook();
// 以原型文檔為原型红且,拷貝一份副本
Book book2 = (Book) book1.clone();
book2.showBook();
// 修改圖書副本坝茎,不會影響原始書本
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的內容是一樣的直焙。而book2修改了“標題”-字符串(基本的數(shù)據類型)景东,并不影響book1的標題,這就保證了book1的安全性奔誓。
淺拷貝引用
public class Client {
public static void main(String[] args) {
// 1.構建書本對象
Book book1 = new Book();
// 2.編輯書本,添加圖片
book1.setTitle("書1");
book1.addImage("圖1");
book1.showBook();
// 以原型文檔為原型搔涝,拷貝一份副本
Book book2 = (Book) book1.clone();
book2.showBook();
// 修改圖書副本厨喂,不會影響原始書本
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----------------------
備注
最后兩個書本內容輸出是一致的。引用類型的新對象book2的image只是單純指向了this.image引用庄呈,并沒有重新構造一個image對象蜕煌,然后將原始書本的圖片添加到新的image對象中,這樣導致book2中的image與原始書本中的是同一個對象诬留。因此斜纪,修改其中一個書本的圖片,另一個書本也會受到影響文兑。
如何解決盒刚?因為Object類的clone方法只會拷貝對象中的基本的數(shù)據類型,對于數(shù)組绿贞、集合因块、容器對象、引用對象等都不會拷貝籍铁;所以采用深拷貝涡上。
深拷貝應用
/**
* 重寫拷貝方法
*/
@Override
protected Book clone() {
try {
Book book = (Book) super.clone();
// 對image對象也調用clone()函數(shù),進行拷貝
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本身吩愧,實現(xiàn)了完全的拷貝,這樣再互不影響增显。