Fork me on GitHub

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咯

  深拷贝和浅拷贝建议不要混合使用,一个类中某些引用使用深拷贝某些引用使用浅拷贝,这是一种非常差的设计,特别是是在涉及到类的继承,父类有几个引用的情况就非常的复杂,建议深拷贝和浅拷贝分开实现。

 

posted @ 2016-08-13 19:21  鹏&鹏  阅读(3616)  评论(11编辑  收藏  举报