java設計模式4——原型模式

java設計模式4——原型模式

一、寫在前面

本節內容與C++語言的複製構造函數、淺拷貝、深拷貝極爲類似,所以建議學習者能夠先了解C++的該部分的相關知識,或者學習完本節內容後,也去了解C++的相應內容,進行比對學習。

二、原型模式介紹

原型模式(Prototype Pattern)是用於建立重複的對象,同時又能保證性能。這種類型的設計模式屬於建立型模式,它提供了一種建立對象的最佳方式。java

這種模式是實現了一個原型接口,該接口用於建立當前對象的克隆。當直接建立對象的代價比較大時,則採用這種模式。例如,一個對象須要在一個高代價的數據庫操做以後被建立。咱們能夠緩存該對象,在下一個請求時返回它的克隆,在須要的時候更新數據庫,以此來減小數據庫調用。程序員

三、java實現克隆的核心

一、實現一個接口(Cloneable)

二、重寫一個方法(clone())

clone()方法的源碼分析

protected native Object clone() throws CloneNotSupportedException;

由方法聲明的放回值類型=>native,可知該方法其實是一個C++封裝好的方法,由java來進行調用,至關於C++語言的複製構造函數,可是又有所區別。數據庫

四、第一種原型模式實現(淺拷貝)

4.一、創建視頻的原型類

package com.xgp.company.建立型模式.第四種_原型模式.demo1;

import java.util.Date;

/**
 * 一、實現一個接口
 * 二、重寫一個方法
 */
//視頻原型類
public class Video implements Cloneable {
    private String name;
    private Date createTime;

    /**
     * 重寫克隆方法
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public Video() {

    }

    public Video(String name, Date createTime) {
        this.name = name;
        this.createTime = createTime;
    }

    public String getName() {
        return name;
    }

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

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    @Override
    public String toString() {
        return "Video{" +
                "name='" + name + '\'' +
                ", createTime=" + createTime +
                '}';
    }
}

4.二、創建複製的客戶端類

package com.xgp.company.建立型模式.第四種_原型模式.demo1;

import java.util.Date;

/**
 * 客戶端:克隆
 */
public class Client {

    public static void main(String[] args) throws CloneNotSupportedException {
        //原型對象
        Video v1 = new Video("狂神說java", new Date());
        System.out.println("v1 = " + v1);
        System.out.println("v1 = " + v1.hashCode());

        System.out.println("========================");
        //v1 克隆 v2
        Video v2 = (Video) v1.clone();
        System.out.println("v2 = " + v2);
        System.out.println("v2 = " + v2.hashCode());

    }
}

運行結果:

v1 = Video{name='狂神說java', createTime=Fri Feb 14 10:26:57 CST 2020}
v1 = 1836019240
========================
v2 = Video{name='狂神說java', createTime=Fri Feb 14 10:26:57 CST 2020}
v2 = 325040804

五、弊端

5.一、揭露弊端的代碼

/**
 * 演示淺克隆弊端
 * @param args
 * @throws CloneNotSupportedException
 */
public static void main(String[] args) throws CloneNotSupportedException {
    //原型對象
    Date date = new Date();
    Video v1 = new Video("狂神說java", date);
    System.out.println("v1 = " + v1);
    System.out.println("v1 = " + v1.hashCode());

    //v1 克隆 v2
    Video v2 = (Video) v1.clone();
    System.out.println("v2 = " + v2);
    System.out.println("v2 = " + v2.hashCode());

    System.out.println("========================");

    date.setTime(22222222);
    System.out.println("v1 = " + v1);
    System.out.println("v1 = " + v1.hashCode());

    //v1 克隆 v2
    System.out.println("v2 = " + v2);
    System.out.println("v2 = " + v2.hashCode());

}

5.二、弊端代碼的運行結果

v1 = Video{name='狂神說java', createTime=Fri Feb 14 10:29:02 CST 2020}
v1 = 1836019240
v2 = Video{name='狂神說java', createTime=Fri Feb 14 10:29:02 CST 2020}
v2 = 325040804
========================
v1 = Video{name='狂神說java', createTime=Thu Jan 01 14:10:22 CST 1970}
v1 = 1836019240
v2 = Video{name='狂神說java', createTime=Thu Jan 01 14:10:22 CST 1970}
v2 = 325040804

5.三、弊端分析

從運行結果能夠看出,當改變一個被v1,v2都引用的時間對象時,二者都發生了改變,沒有將引用的對象進行復制,所以稱之爲淺拷貝。

5.四、模型圖以下:

經過上面的模型圖能夠看到,被引用的對象仍是隻有一份,所以存在很大的弊端。在C++中,若是存在這種引用關閉,當程序員兩次刪除對象時,會出現第二次刪對象時發生異常的狀況。雖然在java語言中,有着gc機制,不須要程序員手動的去釋放對象,不會出現重複刪除的錯誤。可是,當被引用的對象發生改變時,頗有可能會發生數據上的不正確。

六、改進(深拷貝模式)

6.一、咱們指望想要改進後的模型圖以下:被引用的對象也複製了一份,互不干擾。

6.二、實現方式:改造重寫的克隆方法

@Override
protected Object clone() throws CloneNotSupportedException {
    /**
     * 改造克隆方法,進行生克隆
     */
    Object obj = super.clone();
    Video v = (Video) obj;

    //將對象的屬性進行克隆
    v.createTime = (Date) this.createTime.clone();
    return obj;
}

6.三、此時的運行結果爲:

v1 = Video{name='狂神說java', createTime=Fri Feb 14 10:37:33 CST 2020}
v1 = 1836019240
v2 = Video{name='狂神說java', createTime=Fri Feb 14 10:37:33 CST 2020}
v2 = 325040804
========================
v1 = Video{name='狂神說java', createTime=Thu Jan 01 14:10:22 CST 1970}
v1 = 1836019240
v2 = Video{name='狂神說java', createTime=Fri Feb 14 10:37:33 CST 2020}
v2 = 325040804

6.四、當原型引用的對像改變時,複製的對象並不發生改變,被引用的對象被複制了兩份,所以稱之爲深拷貝。

相關文章
相關標籤/搜索