設計模式-原型模式

原型模式也屬于創造型設計模式,他是通過復制一個已經存在的對象實例而得到一個新的實例,避免繁瑣的實例化過程。在這里被復制的對象實例叫做原型,復制原型也叫克隆對象,有深克隆和淺克隆兩種。

淺克隆

對值類型的成員變量進行值的復制,對引用類型的成員變量只復制引用,不復制引用的對象;也就是值類型和引用進行復制

深克隆

在淺克隆的基礎上,對引用類型也進行克隆,而不僅僅是引用

原型克隆的 UML 類圖如下:


client:提出創建對象請求;
propotype:抽象原型,給出所有具體原型需要實現的接口;
concretePropotype:具體的原型對象,需要被復制的對象;

仍然加以代碼實現
先來淺拷貝,抽象原型

public interface Prototype  extends Cloneable {
 public Object clone() ;
}

//具體克隆對象
public class ConcretePropotype implements Propotype {

    private String name;
    private int age;

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

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

客戶端測試下

public class Client {

    public static void main(String[] args) {
        ConcretePropotype propotype=new ConcretePropotype();
        propotype.setName("zhangsan");
        propotype.setAge(11);
        
        ConcretePropotype propotypeClone=(ConcretePropotype) propotype.clone();
        System.out.println(propotypeClone.getName());
        
        propotypeClone.setName("lisi");
        propotypeClone.setAge(12);
        
        System.out.println(propotype.getAge());
        System.out.println(propotypeClone.getName());
    }

}

這個屬于淺克隆,沒有涉及到引用類型,為了驗證下,繼續引入一個對象Student

public class Student {

    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 class ConcretePropotype2 implements Propotype {

    private String name;
    private int age;
    private Student student;

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

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

進入 Client 端進行驗證一下

public class Client2 {

    public static void main(String[] args) {
        ConcretePropotype2 propotype=new ConcretePropotype2();
        Student stu=new Student();
        stu.setAge(50);
        stu.setName("東郭");
        propotype.setStudent(stu);
        
        ConcretePropotype2 propotypeClone=(ConcretePropotype2) propotype.clone();
        propotypeClone.getStudent().setName("西施");
        propotypeClone.getStudent().setAge(100);
        
        System.out.println("原型:"+propotype.getStudent().getName());
        System.out.println("克隆后:"+propotypeClone. getStudent().getName());
        
        System.out.println("原型:"+propotype.getStudent().getAge());
        System.out.println("克隆后:"+propotypeClone. getStudent().getAge());
    }

}

由于是淺克隆,只是引用復制了,所以克隆后把原來的對象也修改了,最后的結果是

原型:西施
克隆后:西施
原型:100
克隆后:100

這個情況就會出現很大問題,把原來的對象徹底修改了,這可是不想遇到的,此時,深克隆粉墨登場,來解決這個問題;但是為了深克隆,需要克隆的對象可序列化,之前的Student對象需要實現public class Student implements Serializable,這樣在 clone 對象里面利用串行化來做深復制。

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 (IOException | ClassNotFoundException e) {
   e.printStackTrace();
   return null;
  }
 }

當然還可以逐個對象的引用進行復制,那樣引用層次較淺還可以接受,太深的話操作性非常不好。還是建議利用串行化來做深復制

深度克隆之后完全就是兩個對象了,互相不干擾,但需要克隆的對象序列化。既然是從克隆出來的,所以依附就小多了,只要產品具有克隆方法就可以克隆一個新的自己出來,再加以演化,就可以很方便的造出不同級別的產品出來。唯一的難點就是何時何地增加克隆方法,以及不能克隆的屬性加以transient標識。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 前言 本文的主要內容如下: 介紹原型模式 示例Java語言的clone淺克隆與深克隆實現深克隆 原型模式的典型應用...
    小旋鋒的簡書閱讀 1,976評論 0 2
  • 定義 原型模式屬于對象的創建模式。通過給出一個原型對象來指明所有創建的對象的類型,然后用復制這個原型對象的辦法創建...
    步積閱讀 1,372評論 0 2
  • 目錄 本文的結構如下: 引言 什么是原型模式 淺克隆和深克隆 clone() 模式的結構 典型代碼 代碼示例 優點...
    w1992wishes閱讀 558評論 0 0
  • 原型模式 介紹 在許多面向對象的應用程序中,有些對象的創建代價過大或者過于復雜。要是可以重建相同的對象并作輕微的改...
    666真666閱讀 461評論 0 2
  • 一、問題的提出在應用程序中,有些對象比較復雜,其創建過程過于復雜,而且我們又需要頻繁的利用該對象,如果這個時候我們...
    Qi0907閱讀 481評論 0 0