【設計模式】Prototype 原型模式

概述:
原型模式是創建型模式的一種,其特點在於通過“複製”一個已經存在的實例來返回新的實例,而不是新建實例。被複制的實例就是我們所稱的“原型”,這個原型是可定製的。原型模式多用於創建複雜的或者耗時的實例,因爲這種情況下,複製一個已經存在的實例使程序運行更高效;或者創建值相等,只是命名不一樣的同類數據。

應用場景:

  • 資源優化場景,類初始化需要消化非常多的資源,這個資源包括數據、硬件資源等。
  • 性能和安全要求的場景,通過new產生一個對象需要非常繁瑣的數據準備或訪問權限,則可以使用原型模式。
  • 一個對象多個修改者的場景,一個對象需要提供給其他對象訪問,而且各個調用者可能都需要修改其值時,可以考慮使用原型模式拷貝多個對象供調用者使用。
  • 在實際項目中,原型模式很少單獨出現,一般是和工廠方法模式一起出現,通過clone的方法創建一個對象,然後由工廠方法提供給調用者。原型模式已經與Java融爲一體,大家可以隨手拿來使用。

複製原型分爲淺克隆與深克隆:
淺克隆:當原型對象被複制時,只複製它本身和其中包含的值類型的成員變量,而引用類型的成員變量並沒有複製。因此兩個對象的interest公共同一個內存地址,一個對象變化,會引起另一個對象響應的變化。

深克隆:除了對象本身被複制外,對象所包含的所有成員變量也將被複制。

下邊用測試代碼來具體闡述兩者的區別
角色分配:
Client:客戶端
Prototype:原型模式中的核心,用於創建原型對象,其實現了Cloneable接口,重寫了clone方法,並將訪問權限改爲public
ConcretePrototype:具體的需要創建的對象的類

測試代碼:

/**
 * @Description 原型模式:實現Cloneable接口,重寫Object的clone方法
 * @date 2019/10/21 16:33
 * @Version V1.0
 */
@Data
public class Prototype implements Cloneable {
    private String name;
    private String context;
    private String title;
    private String address;


    public Prototype(String name, String context, String title, String address) {
        this.name = name;
        this.context = context;
        this.title = title;
        this.address = address;
    }

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

淺克隆:

/**
 * @ClassName Thing
 * @Description 淺拷貝 (1)JVM做了一個偷懶的拷貝動作,Object類提供的方法clone只是拷貝本對象,其對象內部的數組、引用對象等都不拷貝,還是指向原生對象的內部元素地址,這種拷貝就叫做淺拷貝
 * (2)非常不安全
 * @date 2019/10/21 16:45
 * @Version V1.0
 */
@Data
public class Thing implements Cloneable {
    private List<String> list = new ArrayList<String>();
    
    @Override
    protected Thing clone() throws CloneNotSupportedException{
        return (Thing) super.clone();
    }
  }

深克隆:

/**
 * @ClassName Thing2
 * @Description 深拷貝:除了對象本身被複制外,對象所包含的所有成員變量也將被複制
 * @date 2019/10/21 16:50
 * @Version V1.0
 */
@Data
public class Thing2 implements Cloneable {
    private ArrayList<String> list=new ArrayList<String>();

    @Override
    protected Thing2 clone() throws CloneNotSupportedException {
        Thing2 thing2=null;
        thing2=(Thing2) super.clone();
        thing2.list=(ArrayList<String>) this.list.clone();
        return thing2;
    }
  }

測試:

/**
 * @ClassName ClientTest
 * @Description TODO
 * @date 2019/10/21 16:52
 * @Version V1.0
 */
public class ClientTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        test01();
        test02();
        test03();
    }

    /**
     * 原型模式:模板測試
     */
    public static void test01() throws CloneNotSupportedException{
        Prototype mail=new Prototype("sxf", "go smx", "emailtosxf", "[email protected]");//ClientTest.main()com.yeepay.sxf.template8.Mail@2a5330
        System.out.println("ClientTest.main()"+mail.toString());
        Prototype mail2=mail.clone();
        System.out.println("ClientTest.main()"+mail2.toString());//ClientTest.main()com.yeepay.sxf.template8.Mail@18872380
    }
    /**
     * 原型模式:淺拷貝
     */
    public static void test02() throws CloneNotSupportedException{
        Thing thing1=new Thing();
        thing1.setList("小李");
        Thing thing2=thing1.clone();
        thing1.setList("小張");
        List<String> t=thing1.getList();
        List<String> t2=thing2.getList();
        System.out.println("-------------淺克隆開始--------------");
        for (int i = 0; i < t.size(); i++) {
            System.out.println("ClientTest.test02(t==>)"+t.get(i));
        }
        for (int i = 0; i < t2.size(); i++) {
            System.out.println("ClientTest.test02(t2==>)"+t2.get(i));
        }
        System.out.println("-------------淺克隆結束--------------");
    }


    /**
     * 原型模式:深拷貝
     */
    public static void test03() throws CloneNotSupportedException{
        Thing2 thing2a=new Thing2();
        thing2a.setList("小李");
        Thing2 thing2b=thing2a.clone();
        thing2a.setList("小張");
        List<String> t=thing2a.getList();
        List<String> t2=thing2b.getList();
        System.out.println("-------------深克隆開始--------------");
        for (int i = 0; i < t.size(); i++) {
            System.out.println("ClientTest.test02(t==>)"+t.get(i));
        }
        for (int i = 0; i < t2.size(); i++) {
            System.out.println("ClientTest.test02(t2==>)"+t2.get(i));
        }
        System.out.println("-------------深克隆結束--------------");
    }
}

測試結果:
在這裏插入圖片描述
原型設計模式中淺拷貝是將數組和引用對象的指針clone過來了,而深拷貝是將引用對象內部重新分配了內存地址,指針發生了變化。
要使用clone方法,在類的成員變量上就不要增加final關鍵字。

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