設計模式之原型模式

原型模式是一種創建型的模式,原型模式的簡單程度僅次於單例模式和迭代器模式,正是由於簡單,使用的場景非常多。

 



 通過原型模式的通用類圖可以看到,其實原型模式的核心就是一個clone方法,通過該方法實現對象的拷貝。

 

原型模式的優點:

1.原型模式是在內存二進制流的拷貝,要比直接new一個對象性能好很多,特別是要在一個循環體內產生大量對象時。

2.規避構造方法的約束,因爲原型模式是在內存二進制流的拷貝,所以是不會調用構造方法的

 

原型模式的使用場景

1.類的初始化需要消耗非常多的資源(數據、硬件資源等)

2.性能和安全的要求,因爲通過new產生一個對象需要非常繁瑣的數據準備或訪問權限

 

克隆滿足的條件:

 

  clone()方法將對象複製了一份並返還給調用者。所謂“複製”的含義與clone()方法是怎麼實現的。一般而言,clone()方法滿足以下的描述:

 

(1)對任何的對象x,都有:x.clone()!=x。換言之,克隆對象與原對象不是同一個對象。

 

(2)對任何的對象x,都有:x.clone().getClass() == x.getClass(),換言之,克隆對象與原對象的類型一樣。

 

(3)如果對象x的equals()方法定義其恰當的話,那麼x.clone().equals(x)應當成立的。

 

  在JAVA語言的API中,凡是提供了clone()方法的類,都滿足上面的這些條件。JAVA語言的設計師在設計自己的clone()方法時,也應當遵守着三個條件。一般來說,上面的三個條件中的前兩個是必需的,而第三個是可選的。

 

可能分爲淺克隆和深克隆

 

先看一個例子,看看什麼是淺克隆:

 

public class Something implements Cloneable {

    private List<String> list = new ArrayList<String>();

    // 重寫Object類中的clone方法
    @Override
    protected Something clone() {
        Something something = null;

        try {
            something = (Something) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return something;
    }

    public void setValue(String value) {

        this.list.add(value);
    }

    public List<String> getList() {

        return this.list;
    }

    public static void main(String[] args) {
        
        //產生一個對象
        Something something=new Something();
        
        something.setValue("aaa");
        
        //克隆一個對象
        Something thing=something.clone();
        
        thing.setValue("bbb");
        
        System.out.println(something.getList());//結果:[aaa, bbb]

    }

}

 

 

從輸出結果看,這並不是我們想要的拷貝,Object類提供的clone方法只是拷貝對象,對於對象內部的數組、引用對象都不拷貝,還是指向原生對象的內部元素,這種拷貝就是淺拷貝。

 

  •   淺度克隆

 

  只負責克隆按值傳遞的數據(比如基本數據類型、String類型),而不復制它所引用的對象,換言之,所有的對其他對象的引用都仍然指向原來的對象。

 

  •   深度克隆

 

  除了淺度克隆要克隆的值外,還負責克隆引用類型的數據。那些引用其他對象的變量將指向被複制過的新對象,而不再是原有的那些被引用的對象。換言之,深度克隆把要複製的對象所引用的對象都複製了一遍,而這種對被引用到的對象的複製叫做間接複製。

 

  深度克隆要深入到多少層,是一個不易確定的問題。在決定以深度克隆的方式複製一個對象的時候,必須決定對間接複製的對象時採取淺度克隆還是繼續 採用深度克隆。因此,在採取深度克隆時,需要決定多深纔算深。此外,在深度克隆的過程中,很可能會出現循環引用的問題,必須小心處理。

 

下面以一個場景來敘述一下原型模式的使用,相信大家在大學考試的時候都有過打小抄的情況(沒有也不能說明什麼吐舌頭),上一面代理模式中說道小明同學找代理打遊戲,但是人就不去上課,整體的睡懶覺,好了一個學期過去,今天同小強說馬上要考試了,小明很驚訝的說:“不是吧,大學還有考試啊?”此處只能呵呵,那麼小明如何應對考試呢,當然是自己上了這麼多年學積累下來的經驗了,那就是抄別人的.....

 



 

 

代碼如下:

 

 

/**
 * 試卷
 * 
 */
public class Paper implements Cloneable {

    private Student student=new Student();

    @Override
    protected Paper clone() {

        Paper paper = null;

        try {
            paper = (Paper) super.clone();
        } catch (CloneNotSupportedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return paper;
    }

    // 獲取學生信息
    public Student getStudent() {

        return this.student;
    }

    // 獲取考生姓名
    public void setName(String name) {

        this.student.setName(name);
    }

    public int getResult() {

        return 29;
    }

}

 

 

 

/**
 * 
 * 
 */
public class Student {

    // 學生姓名
    private String name;

    // 學生學號
    private String no;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getNo() {
        return no;
    }

    public void setNo(String no) {
        this.no = no;
    }

}

 

 

 

public class Client {

    public static void main(String[] args) {
        
        //生成一份試卷
        Paper paper=new Paper();
        //考生姓名
        paper.setName("小強");
        
        //小明覆制一份小強的試卷
        Paper clonePaper=paper.clone();
        
        clonePaper.setName("小明");
        
        System.out.println(paper.getStudent().getName());
    }
}

 

這段程序的輸出結果是小明,那小強呢?這就是淺拷貝,結果就是兩份試卷的答題人都變成了小明。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章