設計模式--原型設計模式

原型模式理解

當因代碼需要創建大量的重複對象時,比如一個for循環對象集合,每一次循環都要new一個對象來接收,這時的資源開銷比較大。所以,這樣場景下我們就可以選擇使用原型模式用克隆對象替代new對象,在保證需求的同時又能提高性能。

原型模式的實現

深克隆與淺克隆

Java中底層提供了Cloneable接口,使用其中提供的clone()方法就可以實現原型模式。
同時原型模式中克隆對象又分爲淺克隆以及深克隆。

  1. 淺克隆 ,淺克隆只能克隆對象八種基本類型幷包括String類型,不能克隆對象內嵌套的引用對象;
  2. 深克隆,深克隆可以完全克隆對象,包括對象內嵌套的應用對象;

代碼實現

首先我們創建一個原型類Prototype,並實現Java底層的Cloneable接口,並實現clone()方法。
並且爲了直觀的區分淺克隆與深克隆,同時創建兩個原型類中的引用類,其中CloneDepth類爲深克隆類,同樣實現了Cloneable接口以及clone()方法;CloneShallow類爲淺克隆類,不實現Cloneable接口。

/**
 * @Author hezhan
 * @Date 2019/10/23 14:30
 * 用於測試原型設計模式
 */
public class Prototype implements Cloneable {
    private String name;
    private int age;
    private CloneDepth cloneDepth;
    private CloneShallow cloneShallow;

    public CloneShallow getCloneShallow() {
        return cloneShallow;
    }

    public void setCloneShallow(CloneShallow cloneShallow) {
        this.cloneShallow = cloneShallow;
    }

    public CloneDepth getCloneDepth() {
        return cloneDepth;
    }

    public void setCloneDepth(CloneDepth cloneDepth) {
        this.cloneDepth = cloneDepth;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Prototype clone(){
        Prototype prototype = null;
        try {
            prototype = (Prototype)super.clone();
            prototype.setCloneDepth(this.cloneDepth.clone());//深度克隆CloneDepth對象實例
        } catch (CloneNotSupportedException e) {
            throw new RemoteException("克隆Prototype對象實例時出錯");
        }
        return prototype;
    }
}
/**
 * @Author hezhan
 * @Date 2019/10/24 11:30
 * 用於測試原型設計模式(作爲引用對象,淺度克隆部分)
 */
public class CloneShallow {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
/**
 * @Author hezhan
 * @Date 2019/10/23 14:31
 * 用於測試原型設計模式(作爲引用對象,深度克隆部分)
 */
public class CloneDepth implements Cloneable {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public CloneDepth clone(){
        CloneDepth cloneDepth = null;
        try {
            cloneDepth = (CloneDepth)super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RemoteException("克隆CloneDepth對象實例時出錯");
        }
        return cloneDepth;
    }
}

測試類

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {

    /**
     * 測試原型設計模式(淺克隆與深克隆的用法和區別)
     * 若要克隆的對象內部有引用對象(即內部嵌套了其他類的對象),則淺克隆只是克隆了該對象內部引用對象的引用,
     * 並不會獨立出來,修改該對象內部應用對象的屬性會對原型對象造成影響;
     * 而深克隆則會完全複製對象的所有數據,額外開闢空間來存儲複製出來的數據,完全獨立於原型對象,修改克隆對象
     * 的屬性值不會對原型對象造成影響
     */
    @Test
    public void testPrototype() {
        /**
         * 這裏的測試思路爲:
         * 1、首先,cloneDepth對象爲深度克隆,cloneShallow對象爲淺克隆;
         * 2、先爲原型對象prototype以及其內部的引用對象cloneDepth和cloneShallow賦值;
         * 3、然後克隆prototype對象(其中內部引用對象cloneDepth爲深克隆,cloneShallow爲淺克隆);
         * 4、併爲克隆對象prototypeClone以及內部引用對象重新賦值;
         * 5、分別查看原型對象與克隆對象的屬性值;
         * 6、預計結果:由於cloneShallow對象爲淺克隆,所以克隆且爲克隆對象中的應用對象cloneShallow賦值後,
         *    原型對象中的引用對象cloneShallow的屬性值也會被改變。相應的,cloneDepth對象爲深克隆,所以克隆後
         *    賦的值對原型中的引用對象cloneDepth無影響。
         */

        /**
         * 先創建對象
         */
        Prototype prototype = new Prototype();
        CloneDepth cloneDepth = new CloneDepth();
        CloneShallow cloneShallow = new CloneShallow();
        cloneDepth.setName("小貓咪");
        cloneDepth.setAge(1);
        cloneShallow.setName("小狗狗");
        cloneShallow.setAge(2);
        prototype.setAge(3);
        prototype.setName("寵物");
        prototype.setCloneDepth(cloneDepth);
        prototype.setCloneShallow(cloneShallow);
        System.out.println("克隆前每個原型對象屬性的值爲:");
        System.out.println("prototype對象的屬性爲:name=" + prototype.getName() + ",age=" + prototype.getAge());
        System.out.println("cloneDepth對象的屬性爲:name=" + cloneDepth.getName() + ",age=" + cloneDepth.getAge());
        System.out.println("cloneShallow對象的屬性爲:name=" + cloneShallow.getName() + ",age=" + cloneShallow.getAge());
        /**
         * 克隆對象,深度克隆和淺度克隆同時進行,校驗結果
         */
        Prototype prototypeClone = prototype.clone();
        prototypeClone.getCloneDepth().setName("大貓咪");
        prototypeClone.getCloneDepth().setAge(3);
        prototypeClone.getCloneShallow().setName("大狗狗");
        prototypeClone.getCloneShallow().setAge(3);
        prototypeClone.setName("大寵物");
        prototypeClone.setAge(6);
        System.out.println("克隆後每個原型對象屬性的值爲:");
        System.out.println("prototype對象的屬性爲:name=" + prototype.getName() + ",age=" + prototype.getAge());
        System.out.println("cloneDepth對象的屬性爲:name=" + cloneDepth.getName() + ",age=" + cloneDepth.getAge());
        System.out.println("cloneShallow對象的屬性爲:name=" + cloneShallow.getName() + ",age=" + cloneShallow.getAge());
        System.out.println("克隆後每個克隆對象屬性的值爲:");
        System.out.println("prototypeClone:name=" + prototypeClone.getName() + ",age=" + prototypeClone.getAge());
        System.out.println("cloneDepth對象的屬性爲:name=" + prototypeClone.getCloneDepth().getName() + ",age=" + prototypeClone.getCloneDepth().getAge());
        System.out.println("cloneShallow對象的屬性爲:name=" + prototypeClone.getCloneShallow().getName() + ",age=" + prototypeClone.getCloneShallow().getAge());
    }

}

測試結果爲:
測試結果
我們可以看到,原型類中的引用對象cloneShallow爲淺克隆類,所以克隆原型類後,cloneShallow所指向的還是原型類中此引用對象的值,所以修改克隆後的對象屬性發現,原型對象所引用的淺克隆對象也發送了改變。
所以,淺克隆中,原型和克隆類中的引用對象,都指向的是同一個值;而深克隆中,原型和克隆類中的引用對象,指向的是不同的值。

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