原型設計模式 與 深拷貝 淺拷貝

簡介

原型模式(prototype) java中有一個克隆技術,以某個對象爲原型,複製出新的對象。使用克隆,類似於new,但是又不同於new。這是從內存中直接複製了,使用克隆,有效率高的優點,避免了重新執行構造過程的步驟。


原型模式的實現

我們可以想象一下以下一些場景:
火影忍者中,鳴人查克拉的分生。
西遊記中,孫悟空把一根毛變出一堆孫悟空。

這些情況出來的人,都不是一個一個從嬰兒長大的,高效地一會兒就就能在短時間內產出。
即使是現實中的克隆羊多利,其實生命的成長也比普通羊快上不少。(據說因爲他是克隆的6歲的羊,多利一生出來就是6歲,具體不知 (^__^) …)


  • 在prototype模式中 我們首先要cloneable接口實現clone方法,clone方法是在object類裏面的,會自動從object類中繼承
public class Prototype implements Cloneable{
    private String sname;
    private Date  birthday;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        //掉用 object 的克隆方法
        return super.clone();
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public Prototype(String sname, Date birthday) {
        super();
        this.sname = sname;
        this.birthday = birthday;
    }

}

  • 下面我們定義一個 客戶類用於測試
/**
 * 原型方法的測試
 * @author guxiang
 * @date 2017-2-25 上午10:09:27
 */
public class Client {
    public static void main(String[] args) throws Exception {
        Prototype p1 = new Prototype("二狗",new Date());

        Prototype p2 = (Prototype) p1.clone();
        System.out.println(p1);
        System.out.println(p1.getSname());
        System.out.println(p1.getBirthday());
        System.out.println("--------------");
        System.out.println(p2);
        System.out.println(p2.getSname());
        System.out.println(p2.getBirthday());

    }
}


----------
執行結果如下

com.guxiang.prototype.Prototype@6af62373
二狗
Sat Feb 25 11:26:56 CST 2017
--------------
com.guxiang.prototype.Prototype@12276af2
二狗
Sat Feb 25 11:26:56 CST 2017

在執行結果中,我們可以看到, 對象的hash值(內存地址)是不一樣的,代表他們兩個不是一個對象,然而對象裏面屬性的值 都是一樣的,相當於一個克隆人,他不是你,然而屬性和外表都一樣

  • 上面我們講的其實是一種淺拷貝
  • -

什麼是淺拷貝呢?

public class Client {
    public static void main(String[] args) throws Exception {
        Date date = new Date();
        Prototype p1 = new Prototype("二狗",date);
        System.out.println(p1);
        System.out.println(p1.getSname());
        System.out.println(p1.getBirthday());


        Prototype p2 = (Prototype) p1.clone();
        date.setTime(1235);
        System.out.println("--------------");
        System.out.println(p2);
        System.out.println(p2.getSname());
        System.out.println(p2.getBirthday());

    }
}
----------
執行結果如下
com.guxiang.prototype.Prototype@6af62373
二狗
Sat Feb 25 11:50:54 CST 2017
--------------
com.guxiang.prototype.Prototype@12276af2
二狗
Thu Jan 01 08:00:01 CST 1970

我們可以看出,如果原型依賴於另外一個對象,那麼clone的時候,淺拷貝只是拷貝了原型所依賴的對象的地址,而沒有吧原型所依賴的對象拷貝進去。

這裏寫圖片描述


那麼怎麼在原型模式中使用深拷貝呢?


我只需要在克隆的時候 把屬性也克隆。

public class Prototype implements Cloneable{
    private String sname;
    private Date  birthday;


    /**
     * 深拷貝的代碼實現
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        //掉用 object 的克隆方法
        Object object = super.clone();

        Prototype prototype = (Prototype) object;
         prototype.birthday = (Date) this.birthday.clone();

        return prototype;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public Prototype(String sname, Date birthday) {
        super();
        this.sname = sname;
        this.birthday = birthday;
    }

}

深拷貝將原型所依賴的對象 也拷貝了一份
內存圖如下
這裏寫圖片描述

發佈了43 篇原創文章 · 獲贊 91 · 訪問量 22萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章