疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

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咯

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