原型模式(Prototype Pattern)是創建型模式(Creation)的一種,創建型型模式是對類的實例化過程的抽象化,能夠提高對象的創建和管理職責。
原型模式的英文原話是:Specify the kinds of objects to create using a prototypical instance,and create new object by copying this prototype。
意思是,用原型實例指定創建對象的種類,並且通過複製這些原型創建新的對象。
原型模式的UML類圖如下所示:
原型模式共設計3個角色:
抽象原型角色(Prototype):該角色是一個抽象角色,通常由一個Java接口或者抽象類實現,給出所有具體原型類所需的接口;
具體原型模式角色(ConcretePrototype):該角色是被複制的對象,必須實現抽象原型接口;
客戶角色(Client):該角色提出創建對象的請求。
原型模式在生成複雜對象比較苦難的環境中比較適用,通過克隆已有對象來實現創建新的對象,節省了時間和空間。
由於Java語言內置了對象的克隆機制,Object類具有一個clone()方法,能夠實現對象的克隆。
原型模式的實例:
一封電子郵件的主題(標題、收件人、內容...)是相同的,我們希望製作一個電子郵件的原型,以後每次放送郵件,只需複製這個原型,然後填上我們定製的內容,這樣就不用每一次放送都new出一個郵件對象。
抽象原型角色
MailPrototype:
public interface MailPrototype extends Cloneable {
Object clone();
}
具體原型角色:
public class ConcreteMail implements MailPrototype {
private String receiver;
private String subject;
private String contxt;
public ConcreteMail(String subject,String contxt) {
this.subject = subject;
this.contxt = contxt;
}
public ConcreteMail clone() {
try {
return (ConcreteMail)super.clone();
}catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
public String getReceiver() {
return receiver;
}
public void setReceiver(String receiver) {
this.receiver = receiver;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getContxt() {
return contxt;
}
public void setContxt(String contxt) {
this.contxt = contxt;
}
}
客戶角色:
public class Client {
private static int MAX_COUNT = 10;
public static void main(String[] args) {
ConcreteMail mail = new ConcreteMail("Meeting Notice", "There is meeting at 301 5:00pm");
for(int i=0;i<MAX_COUNT;i++) {
mail.clone();
mail.setReceiver("Dear madam/sir: member " + i);
send(mail);
System.out.println("-----------------------------------");
}
}
public static void send(ConcreteMail mail) {
System.out.println("Receiver : " + mail.getReceiver());
System.out.println("Subject : " + mail.getSubject());
System.out.println("\t" + mail.getContxt());
}
}
原型模式的優點:
(1)根據客戶端要求實現動態創建對象,客戶端不需要知道對象的創建細節,便於代碼的維護和擴展。
(2)使用原型模式創建對象比直接new一個對象在性能上要好的多,因爲Object類的clone方法是一個本地方法,它直接操作內存中的二進制流,特別是複製大對象時,性能的差別非常明顯。所以在需要重複地創建相似對象時可以考慮使用原型模式。比如需要在一個循環體內創建對象,假如對象創建過程比較複雜或者循環次數很多的話,使用原型模式不但可以簡化創建過程,而且可以使系統的整體性能提高很多。
(3) 原型模式類似於工廠模式,但它沒有了工廠模式中的抽象工廠和具體工廠的層級關係,代碼結構更清晰和簡單。
原型模式的注意事項:
(1)使用原型模式複製對象不會調用類的構造方法。因爲對象的複製是通過調用Object類的clone方法來完成的,它直接在內存中複製數據,因此不 會調用到類的構造方法。不但構造方法中的代碼不會執行,甚至連訪問權限都對原型模式無效。還記得單例模式嗎?單例模式中,只要將構造方法的訪問權限設置爲 private型,就可以實現單例。但是clone方法直接無視構造方法的權限,所以,單例模式與原型模式是衝突的。
(2)在使用時要注意深拷貝與淺拷貝的問題。clone方法只會拷貝對象中的基本的數據類型,對於數組、容器對象、引用對象等都不會拷貝,這就是淺拷貝。如果要實現深拷貝,必須將原型模式中的數組、容器對象、引用對象等另行拷貝。
幾種創建型模式的區別:
Singleton單件模式解決的問題是:實體對象個數問題(這個現在還不太容易混)
AbstractFactory抽象工廠模式解決的問題是:“一系列互相依賴的對象”的創建工作
Builder生成器模式解決的問題是:“一些複雜對象”的創建工作,子對象變化較頻繁,對算法相對穩定
FactoryMethor工廠方法模式解決的問題是:某個對象的創建工作