java設計模式-----原型模式

1、引言

    原型(Prototype)模式是一種對象建立型模式,他採起復制原型對象的方法來建立對象的實例。使用原型模式建立的實例,具備與原型同樣的數據java

原型模式的特色:設計模式

  1. 由原型對象自身建立目標對象。也就是說,對象建立這一動做發自原型對象自己。
  2. 目標對象是原型對象的一個克隆。也就是說,經過原型模式建立的對象,不只僅與原型對象具備相同的結構,還與原型對象具備相同的值。
  3. 根據對象克隆深度層次的不一樣,有淺度克隆與深度克隆。

  先寫一個支持克隆的類安全

//若是要克隆就必須實現Cloneable接口
public class Person implements Cloneable{
    //可能會拋出不支持克隆異常,緣由是沒有實現Cloneable接口
    @Override
    protected Person clone(){
        try{
            return (Person) super.clone();
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
            return null;
        }
    }
}

這個樣子,就說明這個類能夠克隆了。ide

  這樣克隆函數

public class MainClass {
    public static void main(String[] args) {
        Person person1 = new Person();
        
        Person person2 = person1.clone();
    }
}

       這樣子克隆並不等同於Person p2 = p1;像Person p2 = p1;指的是在棧中建立一個變量p2,將p1的內存地址賦給p2,其實指的是同一個對象。而克隆是複製出一份如出一轍的對象,兩個對象內存地址不一樣,但對象中的結構與屬性值如出一轍。this

  這種不經過 new 關鍵字來產生一個對象,而是經過對象拷貝來實現的模式就叫作原型模式,這個模式的核心是一個clone( )方法,經過這個方法進行對象的拷貝,Java 提供了一個 Cloneable 接口來標示這個對象是可拷貝的,爲何說是「標示」呢?翻開 JDK 的幫助看看 Cloneable 是一個方法都沒有的,spa

這個接口只是一個標記做用,在 JVM 中具備這個標記的對象纔有可能被拷貝,因此覆蓋了覆蓋clone()方法就能夠了。.net

  在 clone()方法上增長了一個註解@Override, 沒有繼承一個類爲何能夠重寫呢?在 Java 中全部類的父類是Object 類,每一個類默認都是繼承了這個類,因此這個用上@Override是很是正確的。原型模式雖然很簡單,可是在 Java 中使用原型模式也就是 clone 方法仍是有一些注意事項的:設計

  對象拷貝時,類的構造函數是不會被執行的。 一個實現了 Cloneable 並重寫了 clone 方法的類 A,有一個無參構造或有參構造 B,經過 new 關鍵字產生了一個對象 S,再而後經過 S.clone()方式產生了一個新的對象 T,那麼在對象拷貝時構造函數 B 是不會被執行的, 對象拷貝時確實構造函數沒有被執行,這個從原理來說也是能夠講得通的,Object 類的 clone 方法的 原理是從內存中(具體的說就是堆內存)以二進制流的方式進行拷貝,從新分配一個內存塊,那構造函數 沒有被執行也是很是正常的了。code

還有就是深度克隆與淺度克隆

首先,是淺度克隆

//若是要克隆就必須實現Cloneable接口
public class Person implements Cloneable{
    private String name;
    private String sex;
    private List<String> list;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public List<String> getList() {
        return list;
    }
    public void setList(List<String> list) {
        this.list = list;
    }
    //可能會拋出不支持克隆異常,緣由是沒有實現Cloneable接口
    @Override
    protected Person clone(){
        try{
            return (Person) super.clone();
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
            return null;
        }
    }
}

這就是淺度克隆,當被克隆的類中有引用對象(String或Integer等包裝類型除外)時,克隆出來的類中的引用變量存儲的仍是以前的內存地址,也就是說克隆與被克隆的對象是同一個。這樣的話兩個對象共享了一個私有變量,全部人均可以改,是一個種很是不安全的方式,在實際項目中使用仍是比較少的。

因此就要說到深度拷貝

//若是要克隆就必須實現Cloneable接口
public class Person implements Cloneable{
    private String name;
    private String sex;
    private List<String> list;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public List<String> getList() {
        return list;
    }
    public void setList(List<String> list) {
        this.list = list;
    }
    //可能會拋出不支持克隆異常,緣由是沒有實現Cloneable接口
    @Override
    protected Person clone(){
        try{
            Person person = (Person) super.clone();
            List<String> newList = new ArrayList();
            
            for(String str : this.list){
                newList.add(str);
            }
            person.setList(newList);
            return person;
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
            return null;
        }
    }
}

這樣就完成了深度拷貝,兩種對象互爲獨立,屬於單獨對象。

注意:final 類型修飾的成員變量不能進行深度拷貝  

  最後說一下,原型模式的使用場景

  一、在建立對象的時候,咱們不僅是但願被建立的對象繼承其基類的基本結構,還但願繼承原型對象的數據。

  二、但願對目標對象的修改不影響既有的原型對象(深度克隆的時候能夠徹底互不影響)。

  三、隱藏克隆操做的細節,不少時候,對對象自己的克隆須要涉及到類自己的數據細節。

  四、類初始化須要消化很是多的資源,這個資源包括數據、硬件資源等;

  五、經過 new 產生一個對象須要很是繁瑣的數據準備或訪問權限,則可使用原型模式;

  六、一個對象須要提供給其餘對象訪問,並且各個調用者可能都須要修改其值時,能夠考慮使用原型模式拷貝多個對象供調用者使用。在實際項目中,原型模式不多單獨出現,通常是和工廠方法模式一塊兒出現,經過 clone的方法建立一個對象,而後由工廠方法提供給調用者。原型模式先產生出一個包含

  大量共有信息的類,而後能夠拷貝出副本,修正細節信息,創建了一個完整的個性對象。

2、總結

        原型模式能夠說是全部設計模式中最簡單的一個,它沒有複雜的繼承體系,只須要使須要具備拷貝功能的類實現Cloneable接口並重寫clone()方法便可。但它的應用卻及其普遍,它將對一個對象中各個字段(不論是私有的仍是共有的)的複製操做封裝在了clone()方法中,這樣,使用該類的用戶就不須要對對象中的各個字段的細節進行了解,直接調用clone()方法就能夠實現對象的拷貝,並且,經過clone()方法還能夠爲不一樣的字段設置被複制的權限,從而容許僅對能夠被複制的字段進行復制。

 

真正勇敢的人,應當可以智慧地忍受最難堪的榮辱,不以身外的榮辱介懷,用息事寧人的態度避免無謂的橫禍。 —— 莎士比亞

相關文章
相關標籤/搜索