23種設計模式(4)-原型模式

worldde發表於2018-02-07

定義:

       通過複製現有的物件例項來建立新的物件例項。

實現:

實現Cloneable介面:

        Cloneable介面的作用是在執行時通知虛擬機器可以安全地在實現了此介面的類上使用clone方法。在java虛擬機器中,只有實現了這個介面的類才可以被拷貝,否則在執行時會丟擲CloneNotSupportedException異常。

重寫Object類中的clone方法:

        Java中,所有類的父類都是Object類,Object類中有一個clone方法,作用是返回物件的一個拷貝,但是其作用域protected型別的,一般的類無法呼叫,因此,原型類需要將clone方法的作用域修改為public型別。

示例:

例如,對於拿郵件發邀請函,郵件類大部分內容都是一樣的:邀請原由、相邀地點,相聚時間等等,但對於被邀請者的名稱和傳送的郵件地址是不同的。

定義Mail類:

public class Mail implements Cloneable {    
    private String receiver;    
    private String subject;    
    private String content;    
    private String tail;    
    public Mail(EventTemplate et) {        
        this.tail = et.geteventContent();        
        this.subject = et.geteventSubject();
    }    
    @Override
    public Mail clone() {
        Mail mail = null;        
    try {
            mail = (Mail) super.clone();            
        } catch (CloneNotSupportedException e) {            
        // TODO Auto-generated catch block
            e.printStackTrace();
        }        return mail;
    }
//get、set.....
}
    測試方法:

public static void main(String[] args) {
    int i = 0;
    int MAX_COUNT = 10;
    EventTemplate et = 
    new EventTemplate("邀請函(不變)", "婚嫁生日啥的....(不變部分)");
    Mail mail = new Mail(et);    
    while (i < MAX_COUNT) {
        Mail cloneMail = mail.clone();
        cloneMail.setContent("XXX先生(女士)(變化部分)"
     + mail.getTail());
        cloneMail.setReceiver("每個人的郵箱地址...com(變化部分)");
        sendMail(cloneMail);
        i++;
    }

}

優點:

        1,使用原型模型建立一個物件比直接new一個物件更有效率,因為它直接操作記憶體中的二進位制流,特別是複製大物件時,效能的差別非常明顯。

        2,隱藏了製造新例項的複雜性,使得建立物件就像我們在編輯文件時的複製貼上一樣簡單。


缺點:

        1,由於使用原型模式複製物件時不會呼叫類的構造方法,所以原型模式無法和單例模式組合使用,因為原型類需要將clone方法的作用域修改為public型別,那麼單例模式的條件就無法滿足了。

        2,使用原型模式時不能有final物件。

        3,Object類的clone方法只會拷貝物件中的基本資料型別,對於陣列,引用物件等只能另行拷貝。這裡涉及到深拷貝和淺拷貝的概念。


深拷貝與淺拷貝:

淺拷貝:

        將一個物件複製後,基本資料型別的變數都會重新建立,而引用型別,指向的還是原物件所指向的(這樣不安全)。

深拷貝:

        將一個物件複製後,不論是基本資料型別還有引用型別,都是重新建立的。

那麼深拷貝如何具體實現呢?

繼續上面的例子,增加了一個ArrayList屬性。

private String receiver;
private String subject;
private String content;
private String tail;
private ArrayList<String> ars;
此時,單mail = (Mail) super.clone();無法將ars指向的地址區域改變,必須另行拷貝:

try {
       mail = (Mail) super.clone();       
       mail.ars = (ArrayList<String>)this.ars.clone();
      } catch (CloneNotSupportedException e) {
          e.printStackTrace();
}

適用場景:

        1,複製物件的結構和資料。

        2,希望對目標物件的修改不影響既有的原型物件。

        3,建立一個物件的成本比較大。


                               閒暇之餘鞏固一下自己的知識體系 ,擴充一下自己的知識面。快利用瑣碎時間給自己充電吧!

相關文章