原型模式

模式定義

用原型實例指定創建對象的種類,并通過拷貝這些原型創建新的對象。

模式結構

模式結構

代碼實現

public interface Prototype {
    Prototype clone();
}

public class ConcretePrototype1 implements Prototype {
    public Prototype clone() {
        return new ConcretePrototype1();
    }
}

public class ConcretePrototype2  implements Prototype {
    public Prototype clone() {
        return new ConcretePrototype2();
    }
}

@AllArgsConstructor
public class Client {
    private Prototype prototype;

    public void operation(){
        Prototype newPrototype = prototype.clone();
    }
}


模式的優缺點

優點

  1. 創建對象的性能高
    使用原型模式創建對象比直接new一個對象在性能上要好的多,因為Object類的clone方法是一個本地方法,它直接操作內存中的二進制流,特別是復制大對象時,性能的差別非常明顯。

  2. 簡化對象的創建

缺點

  1. 克隆的對象的成員變量包含引用類型(String除外)需要特殊處理

  2. 逃避構造方法的約束

  3. 必須實現Cloneable接口

深拷貝和淺拷貝

發生深拷貝的有Java中的8中基本類型以及它們包裝類型,另外還有String類型。其余的都是淺拷貝。

淺拷貝

對值類型的成員變量進行值的復制,對引用類型的成員變量只復制引用,不復制引用的對象。


@Data
@AllArgsConstructor
public class Student implements Cloneable{
    private String studentName;
    private Teacher teacher;

    @Override
    protected Student clone() throws CloneNotSupportedException {
        return (Student) super.clone();
    }

}

@Data
public class Teacher implements Serializable, Cloneable {
    private static final long UID = 6948989635489677685L;

    private String name;

    public Teacher(String name) {
        this.name = name;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Teacher teacher;
        teacher = (Teacher) super.clone();
        return teacher;
    }
}

@Data
public class StudentLow implements Serializable, Cloneable {
    private static final long UID = 6948989635489677685L;
    private String studentName;
    private Teacher teacher;

    public StudentLow(String studentName, Teacher teacher) {
        this.studentName = studentName;
        this.teacher = teacher;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        StudentLow student;
        student = (StudentLow) super.clone();
        return student;
    }

}

public class Client {
    public static void main(String[] args) throws Exception {
        Teacher teacher = new Teacher("snail");

        StudentLow student1 = new StudentLow("wjk", teacher);
        StudentLow student2 = (StudentLow) student1.clone();
        student2.getTeacher().setName("snail改變");

        System.out.println(student1.getTeacher().getName());
        System.out.println(student2.getTeacher().getName());
    }
}

//運行結果(修改克隆的Student的成員變量Teacher的成員變量name導致被克隆的對象的也改變)
snail
snail改變

深拷貝

對值類型的成員變量進行值的復制,對引用類型的成員變量也進行引用對象的復制。

//將上面代碼StudentLow類使用StudentDeep類替換
@Data
public class StudentDeep implements Serializable, Cloneable {
    private static final long UID = 6948989635489677685L;
    private String studentName;
    private Teacher teacher;

    public StudentDeep(String studentName, Teacher teacher) {
        this.studentName = studentName;
        this.teacher = teacher;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        StudentDeep student;
        student = (StudentDeep) super.clone();
        //繼續克隆Teacher
        student.setTeacher((Teacher) this.teacher.clone());
        return student;
    }

    /**
     * 使用序列化實現深拷貝
     */
    /*public Object deepClone() {
        try {
            //將對象寫到流里
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            ObjectOutputStream oo = new ObjectOutputStream(bo);
            oo.writeObject(this);
            //從流里讀出來
            ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
            ObjectInputStream oi = new ObjectInputStream(bi);
            return (oi.readObject());
        } catch (Exception e) {
            return null;
        }
    }*/

}

思考

模式本質:克隆生成對象。

開發中的應用場景

  1. 如果一個系統想要獨立于它想要使用的對象時,可以使用原型模式,讓系統只面向接口編程,在系統需要新的對象的時候,可以通過克隆來得到。

  2. 如果需要實例化的類事在運行時刻動態指定是,可以使用原型模式,通過克隆原型來得到需要的實例。

注意

  1. 使用原型模式不會調用類的構造方法.
    對象的復制是通過調用Object類的clone方法來完成的,它直接在內存中復制數據,因此不會調用到類的構造方法。不但構造方法中的代碼不會執行,甚至連訪問權限都對原型模式無效。還記得單例模式嗎?單例模式中,只要將構造方法的訪問權限設置為private型,就可以實現單例。但是clone方法直接無視構造方法的權限,所以,單例模式與原型模式是沖突的,在使用時要特別注意。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容