Prototype:用原型實例指定建立對象的種類,而且經過拷貝這些原型建立新的對象。java
Prototype適用於在一個類的實例有幾種不一樣的狀態組合的一種時,創建相應的數目的原型並克隆她們,要比每次使用合適的狀態建立它們方便一些,或者爲了不建立一個與產品類層次平行的工廠類層次時,要實例化一的類在運行時動態指定時。ide
假設以下場景:有一個複雜的報表,建立過程很是複雜,須要把報表發給兩個領導,其中只有報表少了屬性不一樣,其餘屬性相同。
首先討論一下java中的基礎知識
java的clone()方法:
clone方法將對象複製一份並返回給調用者。通常知足以下條件:
一、對於任何對象a,都有a.clone()!=x,克隆對象和源對象是不一樣的對象
二、對於任何對象a,都有a.clone().getClass()==a.getClass(),克隆對象和源對象類型同樣
三、若是對象a的equals()方法定義恰當,那麼a.clone().equals(a)成立。
java中對象克隆的實現:
能夠利用Object類的clone()方法
一、對象類實現Coneable接口
二、覆蓋實現clone()方法
三、調用super.clone(),實現克隆。
以上場景實現代碼以下:this
public class Product implements Cloneable{ private String name; private int model; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getModel() { return model; } public void setModel(int model) { this.model = model; } @Override protected Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; } }
public class Report implements Cloneable{ private String name; private Product product; public String getName() { return name; } public void setName(String name) { this.name = name; } public Product getProduct() { return product; } public void setProduct(Product product) { this.product = product; } @Override protected Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; } }
客戶端調用spa
public class App { public static void main( String[] args ){ Report report=new Report(); Product product=new Product(); product.setModel(1); product.setName("productName"); report.setName("某某產品報表"); report.setProduct(product); System.out.println(report.getName()+"|"+report.getProduct().getName()); Report report1=(Report)report.clone(); report1.setName("某某產品報表組1"); report1.getProduct().setName("產品1"); System.out.println(report1.getName()+"|"+report1.getProduct().getName()); } }
以上代碼類圖以下:
指針
深拷貝VS淺拷貝
以上的例子咱們的運行結果以下:code
某某產品報表|productName 某某產品報表組1|產品1
咱們在加一行代碼,在最後一行打印report的信息對象
System.out.println(report.getName()+"|"+report.getProduct().getName());
咱們的運行結果以下:接口
某某產品報表|productName 某某產品報表組1|產品1 某某產品報表|產品1
咱們能夠看出,第二次打印的結果出了問題,report中的產品名字已經被改變了。
在Report中,其中product屬性,咱們引用其餘對象,在clone方法中,咱們的實現只複製了它的引用,只負責了它的指針,沒有複製它所指向的堆空間裏的屬性,因此在這行代碼report1.getProduct().setName("產品1");也改變了report中product屬性中的name屬性的值,這種拷貝是淺拷貝。
咱們修改下report的clone()方法,改成以下:get
@Override protected Object clone() { Report report; try { report=(Report) super.clone(); report.setProduct((Product)product.clone()); return report; } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; }
咱們再看下運行結果原型
某某產品報表|productName 某某產品報表組1|產品1 某某產品報表|productName
此次結果正確了,在以上代碼中,咱們對product屬性,也進行了一次clone,因此report1和report的product屬性指向了不一樣的堆空間,因此咱們改變product中的屬性值,不會相互影響,這個拷貝就是深拷貝。