设计模式-Prototype

来源:互联网 发布:手机电脑无线传数据 编辑:程序博客网 时间:2024/05/29 13:42

定义:是一种创建型设计模式,它通过复制一个已经存在的实例来返回新的实例,而不是新建实例.被复制的实例就是我们所称的原型,这个原型是可定制的.

重点:
1、原型模式主要用于对象的复制,Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节。

2、使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显

应用场景:原型模式多用于创建复杂的或者耗时的实例, 因为这种情况下,复制一个已经存在的实例可以使程序运行更高效,或者创建值相等,只是命名不一样的同类数据.
图片

class Prototype implements Cloneable {      public Prototype clone(){          Prototype prototype = null;          try{              prototype = (Prototype)super.clone();          }catch(CloneNotSupportedException e){              e.printStackTrace();          }          return prototype;       }  }  class ConcretePrototype extends Prototype{      public void show(){          System.out.println("原型模式实现类");      }  }  public class Client {      public static void main(String[] args){          ConcretePrototype cp = new ConcretePrototype();          ConcretePrototype clonecp = (ConcretePrototype)cp.clone();          clonecp.show();    }  }

输出:

原型模式实现类

扩展: 1、clone方法构造的对象是没有调用构造方法的

class Prototype implements Cloneable {  public Prototype clone() {    Prototype prototype = null;    try {      prototype = (Prototype) super.clone();    } catch (CloneNotSupportedException e) {      e.printStackTrace();    }    return prototype;  }}class ConcretePrototype extends Prototype {  private static int i = 0;  public ConcretePrototype() {    i++;  }  public void show() {    System.out.println("原型模式实现类" + i);  }}public class Test {  public static void main(String[] args) {    ConcretePrototype cp = new ConcretePrototype();    ConcretePrototype clonecp = (ConcretePrototype) cp.clone();    System.out.println(cp == clonecp);    System.out.println(cp.equals(clonecp));    cp.show();    clonecp.show();  }}

输出:

false

false

原型模式实现类1

原型模式实现类1

如果是走了构造方法,clonecp.show();应该输出2

2、引用只会进行浅拷贝 (prototype 和 clone 的引用实例:是同一个对象)

class P implements Cloneable {  public P clone() {    P prototype = null;    try {      prototype = (P) super.clone();    } catch (CloneNotSupportedException e) {      e.printStackTrace();    }    return prototype;  }}/** * 引用只会进行浅拷贝, * @author xinchun.wang */public class A extends P {  private List<String> list = new ArrayList<String>();  private String s = "s";  public static void main(String[] args) {    A a = new A();    A ca = (A)a.clone();    System.out.println(a.equals(ca));//false    System.out.println(a.list == ca.list); //true    a.list.add("aaa");    System.out.println(ca.list); //[aaa]    System.out.println("---------------------------");    System.out.println("a.s: " + a.s);//a.s:s    System.out.println("ca.s: " + ca.s);//ca.s: s    a.s = "b";    System.out.println("a.s: " + a.s);//a.s: b    System.out.println("ca.s: " + ca.s);//ca.s: s  }}

3、深拷贝与浅拷贝
Object类的clone方法只会拷贝对象中的基本的数据类型(8种基本数据类型byte,char,short,int,long,float,double,boolean),对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的引用对象(数组、容器对象)另行拷贝。

举例

public class Prototype implements Cloneable {      private ArrayList list = new ArrayList();      public Prototype clone(){          Prototype prototype = null;          try{              prototype = (Prototype)super.clone();              prototype.list = (ArrayList) this.list.clone();          }catch(CloneNotSupportedException e){              e.printStackTrace();          }          return prototype;       }  }

注意:由于ArrayList不是基本类型,所以成员变量list,不会被拷贝,需要我们自己实现深拷贝,幸运的是java提供的大部分的容器类都实现了Cloneable接口。所以实现深拷贝并不是特别困难。

以下是 ArrayList的clone实现,其他引用实现可以参考:

public Object clone() {  try {      ArrayList<E> v = (ArrayList<E>) super.clone();      v.elementData = Arrays.copyOf(elementData, size);      v.modCount = 0;      return v;  } catch (CloneNotSupportedException e) {      // this shouldn't happen, since we are Cloneable      throw new InternalError();  }    }

4、深拷贝的实现举例:

class P implements Cloneable {}/** * @author xinchun.wang */public class A extends P {  @SuppressWarnings("unchecked")  public A clone() {    A prototype = null;    try {      prototype = (A) super.clone();      prototype.list = (List<String>) ((ArrayList<String>)(this.list)).clone();    } catch (CloneNotSupportedException e) {      e.printStackTrace();    }    return prototype;  }  private List<String> list = new ArrayList<String>();  public static void main(String[] args) {    A a = new A();    A ca = a.clone();    a.list.add("aaaa");    System.out.println(a.list); //[aaaa]    System.out.println(ca.list);//[]  }}

还有一种方式:

序列化实现,把对象写道流里的过程是串行化(Serilization)过程;把对象从流中读出来是并行化(Deserialization)过程. 写在流里的是对象的一个拷贝,然后再从流里读出来重建对象.

public class PrototypeSe implements Serializable { private String name; public String getName() {  return name; } public void setName(String name) {  this.name = name; }}public class NewPrototypeSe implements Serializable { private String id; public String getId() {  return id; } public void setId(String id) {  this.id = id; } private PrototypeSe prototype; public PrototypeSe getPrototype() {  return prototype; } public void setPrototype(PrototypeSe prototype) {  this.prototype = prototype; } public Object deepClone(){  try {   ByteArrayOutputStream bo = new ByteArrayOutputStream();   ObjectOutputStream oo = new ObjectOutputStream(bo);      oo.writeObject(this);      ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());   ObjectInputStream oi = new ObjectInputStream(bi);   return oi.readObject();   } catch (IOException | ClassNotFoundException e) {   // TODO Auto-generated catch block   e.printStackTrace();   return null;  } }}public class TestDeepClone { public static void main(String[] args) {  // TODO Auto-generated method stub  PrototypeSe po = new PrototypeSe();  po.setName("test1");  NewPrototypeSe se = new NewPrototypeSe();  se.setPrototype(po);  NewPrototypeSe deepClone = (NewPrototypeSe)se.deepClone();  deepClone.getPrototype().setName("test2");  System.out.println("original name:" + se.getPrototype().getName());  System.out.println("cloned name:" + deepClone.getPrototype().getName()); }}

结果:

original name:test1
cloned name:test2

0 0
原创粉丝点击