java設計模式之原型模式


原型模式概念

  該模式的思想就是將一個對象作為原型,對其進行復制、克隆,產生一個和原對象類似的新對象。java中復制通過clone()實現的。clone中涉及深、淺復制。深、淺復制的概念如下:

  ⑴淺復制(淺克隆) 

      被復制對象的所有變量都含有與原來的對象相同的值,而所有的對其他對象的引用仍然指向原來的對象。換言之,淺復制僅僅復制所考慮的對象,而不復制它所引用的對象。 Object類提供的方法clone只是拷貝本對象,其對象內部的數組、引用對象等都不拷貝,還是指向原生對象的內部元素地址

  ⑵深復制(深克隆) 

      被復制對象的所有變量都含有與原來的對象相同的值,除去那些引用其他對象的變量。那些引用其他對象的變量將指向被復制過的新對象,而不再是原有的那些被引用的對象。換言之,深復制把要復制的對象所引用的對象都復制了一遍。 

原型模式代碼

package com.roc.prototype;

import java.io.Serializable;
/**
 * 原型模式   程序員
 * @author liaowp
 *
 */
public class Programmer implements Serializable,Cloneable{
    
    /**
     * 
     */
    private static final long serialVersionUID = 3078949912404836178L;
    
    private String name;

    public String getName() {
        return name;
    }

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

    public Programmer clone() throws CloneNotSupportedException {  
        Programmer proto = (Programmer) super.clone();  
        return proto;  
    }  
}

下面寫一個淺復制的例子

package com.roc.prototype;
/**
 * 地址
 * @author liaowp
 *
 */
public class Address{

    private String province;//
    
    private String city;//
    
    public Address(String province,String city){
        this.province=province;
        this.city=city;
    }

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    } 
}
package com.roc.prototype;

/**
 * 原型模式   程序員
 * @author liaowp
 *
 */
public class Programmer implements Cloneable{
    
    
    private String name;//名字
    
    private  Address address;

    public Programmer(String name,Address address){
        this.name=name;
        this.address=address;
    }
    
    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public String getName() {
        return name;
    }

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

    public Object clone() throws CloneNotSupportedException {  
        Programmer proto = (Programmer) super.clone();  
        return proto;  
    }  
    
}
package com.roc.prototype;
/**
 * 原型模式
 * @author liaowp
 *
 */
public class Client {
    
    public static void main(String[] args) throws CloneNotSupportedException {    
        //淺復制復制
        Address address=new Address("jx","gz");
        Programmer a=new Programmer("liaowp",address);
        a.setAddress(new Address("jx", "gz"));
        a.setName("liaowp");
        Programmer b=(Programmer) a.clone();
        b.setName("pwl");
        b.getAddress().setProvince("bj");
        System.err.println(b.getName()+b.getAddress().getProvince());
        System.err.println(a.getName()+a.getAddress().getProvince());    
    }
}

  輸出結果:pwlbj

                   liaowpbj

  可以看出來對象並復制,依然使用的是同一個引用。其對象內部的數組、引用對象等都不拷貝,還是指向原生對象的內部元素地址。下面看深復制的寫法,深復制有2種寫法,一種是對象實現Cloneable,另外一種是二進制流。我都一起寫了。

package com.roc.prototype;

/**
 * 原型模式   程序員
 * @author liaowp
 *
 */
public class Programmer implements Cloneable{
    
    
    private String name;//名字
    
    private  Address address;

    public Programmer(String name,Address address){
        this.name=name;
        this.address=address;
    }
    
    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public String getName() {
        return name;
    }

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

    public Object clone() throws CloneNotSupportedException {  
        Programmer proto = (Programmer) super.clone();  
        proto.address=(Address) address.clone();
     return proto; } }
package com.roc.prototype;
/**
 * 地址
 * @author liaowp
 *
 */
public class Address implements Cloneable{

    private String province;//
    
    private String city;//
    
    public Object clone(){ Address address = null; try { address = (Address) super.clone(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block
 e.printStackTrace(); } return address; }
  public Address(String province,String city){ this.province=province; this.city=city; } public String getProvince() { return province; } public void setProvince(String province) { this.province = province; } public String getCity() { return city; } public void setCity(String city) { this.city = city; }

    /* 深復制 */ 二進制的寫法,需要類序列化

    public Object deepClone() throws IOException, ClassNotFoundException {

      /* 寫入當前對象的二進制流 */
      ByteArrayOutputStream bos = new ByteArrayOutputStream();
      ObjectOutputStream oos = new ObjectOutputStream(bos);
      oos.writeObject(this);

      /* 讀出二進制流產生的新對象 */
      ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
      ObjectInputStream ois = new ObjectInputStream(bis);
      return ois.readObject();
  }

}

package com.roc.prototype;
/**
 * 原型模式
 * @author liaowp
 *
 */
public class Client {
    
    public static void main(String[] args) throws CloneNotSupportedException {
        //淺復制復制
        Address address=new Address("jx","gz");
        Programmer a=new Programmer("liaowp",address);
        a.setAddress(new Address("jx", "gz"));
        a.setName("liaowp");
        Programmer b=(Programmer) a.clone();
        b.setName("pwl");
        b.getAddress().setProvince("bj");
        System.err.println(b.getName()+b.getAddress().getProvince());
        System.err.println(a.getName()+a.getAddress().getProvince());
    }
}

結果:pwlbj

    liaowpjx

   拷貝還有2個知識點,對象拷貝時,類的構造函數是不會被執行的。一個實現了 Cloneable 並重寫了 clone 方法的類 Programmer,有一個無參構造或有參構造 ,通過 new 關鍵字產生了一個對象 A,再然后通過 A.clone()方式產生了一個新的對象 T,那么在對象拷貝時構造函數是不會被執行的。即拷貝的過程中只執行一次構造方法。

  Clone 與 final 兩對冤家。對象的 clone 與對象內的 final 屬性是由沖突.在上面的Programmer類中修改為private final Address address;去掉get,set方法, proto.address=(Address) address.clone();這一句就會報錯: proto.address=(Address) address.clone();final類型不能重新設置值。解決辦法就是刪除掉fina咯

  深拷貝和淺拷貝建議不要混合使用,一個類中某些引用使用深拷貝某些引用使用淺拷貝,這是一種非常差的設計,特別是是在涉及到類的繼承,父類有幾個引用的情況就非常的復雜,建議深拷貝和淺拷貝分開實現。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM