設計模式學習--Prototype

來源:互聯網
上載者:User

標籤:設計模式   prototype   

What

Prototype:用原型執行個體指定建立對象的種類,並且通過拷貝這些原型建立新的對象。

Why

Prototype適用於在一個類的執行個體有幾種不同的狀態組合的一種時,建立相應的數目的原型並複製她們,要比每次使用合適的狀態建立它們方便一些,或者為了避免建立一個與產品類層次平行的工廠類層次時,要執行個體化一的類在運行時動態指定時。

How

假設如下情境:有一個複雜的報表,建立過程非常複雜,需要把報表發給兩個領導,其中只有報表少了屬性不同,其他屬性相同。
首先討論一下java中的基礎知識
java的clone()方法:
clone方法將對象複製一份並返回給調用者。一般滿足如下條件:
1、對於任何對象a,都有a.clone()!=x,複製對象和來源物件是不同的對象
2、對於任何對象a,都有a.clone().getClass()==a.getClass(),複製對象和來源物件類型一樣
3、如果對象a的equals()方法定義恰當,那麼a.clone().equals(a)成立。
java中對象複製的實現:
可以利用Object類的clone()方法
1、對象類實現Coneable介面
2、覆蓋實現clone()方法
3、調用super.clone(),實現複製。
以上情境實現代碼如下:

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;    }}

用戶端調用

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());    }}

以上代碼類圖如下:

Discuss

深拷貝VS淺拷貝
以上的例子我們的運行結果如下:

某某產品報表|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()方法,改為如下:

    @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中的屬性值,不會相互影響,這個拷貝就是深拷貝。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.