GOF23-原型模式

原型模式:以現有對象爲原型,克隆新的一模一樣的對象。減少通過構造方法新建對象時分配屬性、方法的權限時間。

原型方法實現方式:實現Cloneable接口(標記接口)和Object.clone()方法、序列化實現複製。

一、實現Cloneable接口(標記接口)和Object.clone()方法(在破解單例模式中使用過)

通過java提供的Cloneable接口方式實現原型模式,分爲淺克隆和深克隆。 

1.淺克隆

package prototype;

import java.util.Date;

public class Sheep implements Cloneable{
    //基本類型
    private String name;
    //對象
    private Date birthday;
    /**
     * 此方法在object方法中 Cloneable接口是一個空接口 調用的是本地方法
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Sheep obj = (Sheep) super.clone();
        return obj;
    }

    public String getName() {
        return name;
    }

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

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

測試代碼

package prototype;

import java.util.Date;

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Sheep sheep = new Sheep();
        sheep.setName("小羊");
        sheep.setBirthday(new Date(123213));
        
        Sheep sheep2 = (Sheep) sheep.clone();
        Date birthday = sheep.getBirthday();
        birthday.setTime(123312323);
        sheep.setName("大羊");
        
        System.out.println(sheep.getName());
        System.out.println(sheep.getBirthday().toString());
        System.out.println(sheep2.getName());
        System.out.println(sheep2.getBirthday().toString());
    }
}

結果

總結:通過object的clone方法克隆的對象,當對象的屬性爲非基本類型時,克隆對象和被克隆對象中是同一個對象。內存示意圖如下克隆是克隆屬性的值(在java中全是值傳遞,當屬性爲非基本類型時屬性存儲的是 對象內存地址的值)

2.深克隆

爲了解決上一問題,我們需要對象也爲新克隆出來的對象。 那麼我們需要重寫clone方法。

@Override
protected Object clone() throws CloneNotSupportedException {
    Sheep obj = (Sheep) super.clone();
    obj.birthday = (Date) this.birthday.clone();
    return obj;
}

增加了屬性對象的單獨克隆obj.birthday = (Date) this.birthday.clone(); 實現深克隆

二、通過序列化實現深克隆

序列化對象實現Serializable接口 ,其他不用修改

測試代碼

package prototype;

import java.io.*;
import java.util.Date;

public class Client2 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Sheep sheep = new Sheep();
        sheep.setName("小羊");
        sheep.setBirthday(new Date(123213));
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(sheep);
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        Sheep sheep2 = (Sheep) ois.readObject();
        sheep.getBirthday().setTime(11111111);
        System.out.println(sheep.getName());
        System.out.println(sheep.getBirthday().toString());
        System.out.println(sheep2.getName());
        System.out.println(sheep2.getBirthday().toString());
    }
}

測試結果

三、性能對比,測試代碼都是根據實際使用代碼,如你有差異,請指出共同勉進,謝謝

package prototype;

import java.io.*;
import java.util.Date;

public class Client3 {
    static int MAXCYCLIC = 100000;
    public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
        Sheep sheep = new Sheep();
        sheep.setName("小羊");
        sheep.setBirthday(new Date(123213));

        Long start = System.currentTimeMillis();
        for(int i=0; i<MAXCYCLIC;i++){
            Sheep sheep1 = new Sheep();
            sheep.setName("小羊");
            sheep.setBirthday(new Date(123213));
        }
        Long end = System.currentTimeMillis();
        System.out.println("構造方法創建對象所需時間"+(end-start));

        start = System.currentTimeMillis();
        for(int i=0; i<MAXCYCLIC;i++){
            Sheep sheep1 = (Sheep) sheep.clone();
        }
        end = System.currentTimeMillis();
        System.out.println("克隆接口方式創建對象所需時間"+(end-start));

        start = System.currentTimeMillis();
        for(int i=0; i<MAXCYCLIC;i++){
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(sheep);
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            Sheep sheep2 = (Sheep) ois.readObject();
            ois.close();
            bais.close();
            oos.close();
            baos.close();
        }
        end = System.currentTimeMillis();
        System.out.println("序列化方式創建對象所需時間"+(end-start));

    }
}

測試結果(每次結果根據電腦資源情況 會不一致):序列化方式因爲存在 輸入輸出流的創建和關閉非常耗資源和時間。

 

總結:接口克隆方式性能高但是我們需要更關注代碼的實現,序列化方式簡單粗暴,但是性能相對低, 看具體情況擇優選擇。

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