設計模式(七)原型模式

版權聲明:轉載必須註明本文轉自曉_晨的博客:http://blog.csdn.net/niunai112

目錄

導航

設計模式之六大設計原則
設計模式(一)單例模式
設計模式(二)工廠模式
設計模式(三)策略模式
設計模式(四)適配器模式
設計模式(五)享元模式
設計模式(六)建造者模式
設計模式(七)原型模式
設計模式(八)橋接模式
設計模式(九)外觀模式
設計模式(十)組合模式
設計模式(十一)裝飾器模式
設計模式(十二)代理模式
設計模式(十三)迭代器模式
設計模式(十四)觀察者模式
設計模式(十五)中介者模式
設計模式(十六)命令模式
設計模式(十七)狀態模式
設計模式(十八)訪問者模式
設計模式(十九)責任鏈模式
設計模式(二十)解釋器模式
設計模式(二十一)備忘錄模式
設計模式(二十二)模板模式
設計模式總結篇(爲什麼要學習設計模式,學習設計模式的好處)

前言

原型模式:用原型實例指定創建對象的種類,並且通過複製這些原型創建新的對象。被複制的實例被稱爲原型,這個原型是可定製的。
在Java中,jdk提供了語言級的支持,只要對象實現了Cloneable接口,重寫clone方法,即可賦值對象。但在賦值對象中要注意淺層複製與深層複製的區別。LZ會在接下來的例子中講清楚。

例子

在一個遊戲中,假如我們需要創建大量的士兵的話,傳統的方法是我們需要不停的new出來對象,但是假如new對象的創建過程非常耗時的話,那麼我們就要花費大量的時間在創建對象上了,那這部分時間我們能不能省下來呢?答案就在原型模式上。

淺層複製,對於複製出來的對象字段是引用已有的內存空間

/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 14:27 2018/3/21
 *@Modified By:
 *
 */
public class Soldier implements Cloneable{

    Integer hp;
    int mp;
    String name;
    DeepCopy deepCopy;
    public Object clone() {
        Object clone = null;
        try {
            clone = super.clone();

        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }
}


/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 10:24 2018/3/21
 *@Modified By:
 *
 */
public class Test {
        public static void main(String[] args) {
        Soldier soldier = new Soldier();
        soldier.hp = new Integer(5000);
        soldier.mp = 1;
        soldier.name = "1";
        soldier.deepCopy = new DeepCopy();
        soldier.deepCopy.attribute1 = "attribute1";


        Soldier cloneSoldier = (Soldier)soldier.clone();
        System.out.println("原始士兵的deepCopy的attribute1的值:" + soldier.deepCopy.attribute1);

        System.out.println("克隆對象的deepCopy的attribute1的值:" + cloneSoldier.deepCopy.attribute1);

        cloneSoldier.deepCopy.attribute1 = "changeAttribute";
        System.out.println("修改克隆對象的deepCopy的attribute1的值後,原始士兵的deepCopy的attribute1值:" + soldier.deepCopy.attribute1);
        System.out.println("修改克隆對象的deepCopy的attribute1的值後,克隆對象的deepCopy的attribute1值:" + cloneSoldier.deepCopy.attribute1);

    }
}
運行結果如下
--------------------------
原始士兵的deepCopy的attribute1的值:attribute1
克隆對象的deepCopy的attribute1的值:attribute1
修改克隆對象的deepCopy的attribute1的值後,原始士兵的deepCopy的attribute1值:changeAttribute
修改克隆對象的deepCopy的attribute1的值後,克隆對象的deepCopy的attribute1值:changeAttribute


UML圖
prototype

深層克隆,對於複製出來的對象字段也複製一個新的空間,並引用到新的空間。


/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 10:23 2018/3/21
 *@Modified By:
 *
 */
public class Soldier implements Cloneable{
    public Integer hp;
    public int mp;
    public String name;
    public DeepCopy deepCopy;
    public Object clone() {
        Object clone = null;
        Soldier clone1 = null;
        try {
            clone = super.clone();
            clone1 = (Soldier) clone;
            clone1.deepCopy = (DeepCopy) this.deepCopy.clone();

        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone1;
    }
}

/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 10:44 2018/3/21
 *@Modified By:
 *
 */
public class DeepCopy implements Cloneable{
    public String attribute1;
    public String attribute2;
    public DeepCopy(){
        for (int i = 0; i < 10000; i++){
            this.attribute1 = "" + i;
        }

    }
    public Object clone() {
        Object clone = null;
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }
}

    public class Test {
    public static void main(String[] args) {
        Soldier soldier = new Soldier();
        soldier.hp = new Integer(5000);
        soldier.mp = 1;
        soldier.name = "1";
        soldier.deepCopy = new DeepCopy();
        soldier.deepCopy.attribute1 = "attribute1";


        Soldier cloneSoldier = (Soldier)soldier.clone();
        System.out.println("原始士兵的deepCopy的attribute1的值:" + soldier.deepCopy.attribute1);

        System.out.println("克隆對象的deepCopy的attribute1的值:" + cloneSoldier.deepCopy.attribute1);

        cloneSoldier.deepCopy.attribute1 = "changeAttribute";
        System.out.println("修改克隆對象的deepCopy的attribute1的值後,原始士兵的deepCopy的attribute1值:" + soldier.deepCopy.attribute1);
        System.out.println("修改克隆對象的deepCopy的attribute1的值後,克隆對象的deepCopy的attribute1值:" + cloneSoldier.deepCopy.attribute1);

    }
}

運行結果如下
---------------------------------------
原始士兵的deepCopy的attribute1的值:attribute1
克隆對象的deepCopy的attribute1的值:attribute1
修改克隆對象的deepCopy的attribute1的值後,原始士兵的deepCopy的attribute1值:attribute1
修改克隆對象的deepCopy的attribute1的值後,克隆對象的deepCopy的attribute1值:changeAttribute

這樣修改裏面的屬性就不會影響到原始對象了,clone多個也不會相互影響。

對比

這裏專門新建了一個原型模式比新建對象快多少的測試模型

public class Soldier implements Cloneable{
    public Integer hp;
    public int mp;
    public String name;
    public DeepCopy deepCopy;
    public Object clone() {
        Object clone = null;
        Soldier clone1 = null;
        try {
            clone = super.clone();
            clone1 = (Soldier) clone;
            clone1.deepCopy = (DeepCopy) this.deepCopy.clone();

        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone1;
    }
}

public class DeepCopy implements Cloneable{
    public String attribute1;
    public String attribute2;
    public DeepCopy(){


    }
    public Object clone() {
        Object clone = null;
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }
}

/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 10:24 2018/3/21
 *@Modified By:
 *
 */
public class Test {

    public static void main(String[] args) {
        Soldier soldier = new Soldier();
        soldier.hp = 1;
        soldier.mp = 1;
        soldier.name = "1";
        soldier.deepCopy = new DeepCopy();

        long begin = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++){
            Soldier soldier1 = new Soldier();
            soldier1.deepCopy = new DeepCopy();
        }
        long end = System.currentTimeMillis();
        System.out.println("新建10000個對象耗時:" + (end - begin));


        begin = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++){

            soldier.clone();
        }
        end = System.currentTimeMillis();
        System.out.println("克隆10000個對象耗時:" + (end - begin));

    }
}
運行結果如下
-----------------------------------------
新建10000個對象耗時:1
克隆10000個對象耗時:3

是不是覺得很奇怪,用了原型模式反而變慢了?不要急,我們在DeepCopy裏的默認構造方法裏假如for循環來模擬耗時操作

/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 10:44 2018/3/21
 *@Modified By:
 *
 */
public class DeepCopy implements Cloneable{
    public String attribute1;
    public String attribute2;
    public DeepCopy(){
        for (int i = 0; i < 10000; i++){
            this.attribute1 = "" + i;
        }

    }
    public Object clone() {
        Object clone = null;
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }
}
運行結果如下
---------------------------
新建10000個對象耗時:1791
克隆10000個對象耗時:2

好了,大家應該可以看出差距了吧,因爲克隆對象不需要調用新建對象的構造函數,而是直接用對內存進行復制的操作,所以,構造函數越耗時,那麼用原型模式的收益就越高。而假如構造函數不復雜,那麼使用原型模式會略微增加一點性能消耗,但是相比第二個對比的收益來說,原型模式增加一點性能消耗根本微乎其微。

總結

原型模式的Prototype類必須繼承Cloneable接口,並對接口中的clone方法進行實現,主要的優點與缺點如下:

優點

(1):使用原型模型創建一個對象比直接new一個對象更有效率,因爲它直接操作內存中的二進制流,特別是複製大對象時,性能的差別非常明顯。

(2):隱藏了製造新實例的複雜性,使得創建對象就像我們在編輯文檔時的複製粘貼一樣簡單。

缺點

(1):需要爲每一個類配置一個克隆方法,而且該克隆方法位於類的內部,當對已有類進行改造的時候,需要修改代碼,違反了開閉原則。

(2):在實現深克隆時需要編寫較爲複雜的代碼,爲了實現深克隆,每一層對象對應的類都必須支持深克隆,實現起來會比較麻煩。

Git地址

本篇實例Github地址:https://github.com/stackisok/Design-Pattern/tree/master/src/prototype
有什麼不懂或者不對的地方,歡迎留言。

回到最上方


喜歡LZ文章的小夥伴們,可以關注一波,也可以留言,LZ會回你們的。
覺得寫得不錯的小夥伴,歡迎轉載,但請附上原文地址,謝謝^_^!

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