设计模式-Prototype
程序员文章站
2022-03-05 22:13:13
...
学习参考:
http://www.cnblogs.com/hegezhou_hot/archive/2010/12/04/1896471.html
定义:是一种创建型设计模式,它通过复制一个已经存在的实例来返回新的实例,而不是新建实例.被复制的实例就是我们所称的原型,这个原型是可定制的.
重点:
1、原型模式主要用于对象的复制,Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节。
2、使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显
应用场景:原型模式多用于创建复杂的或者耗时的实例, 因为这种情况下,复制一个已经存在的实例可以使程序运行更高效,或者创建值相等,只是命名不一样的同类数据.
类图:
JDK中的体现:
Object.clone;Cloneable
输出:
原型模式实现类
扩展:
1、clone方法构造的对象是没有调用构造方法的
输出:
false
false
原型模式实现类1
原型模式实现类1
如果是走了构造方法,clonecp.show();应该输出2
2、引用只会进行浅拷贝 (prototype 和 clone 的引用实例:是同一个对象)
3、深拷贝与浅拷贝
Object类的clone方法只会拷贝对象中的基本的数据类型(8种基本数据类型byte,char,short,int,long,float,double,boolean),对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的引用对象(数组、容器对象)另行拷贝。
举例:
注意:由于ArrayList不是基本类型,所以成员变量list,不会被拷贝,需要我们自己实现深拷贝,幸运的是java提供的大部分的容器类都实现了Cloneable接口。所以实现深拷贝并不是特别困难。
以下是 ArrayList的clone实现,其他引用实现可以参考:
4、深拷贝的实现举例:
还有一种方式:
序列化实现,把对象写道流里的过程是串行化(Serilization)过程;把对象从流中读出来是并行化(Deserialization)过程. 写在流里的是对象的一个拷贝,然后再从流里读出来重建对象.
结果:
original name:test1
cloned name:test2
http://www.cnblogs.com/hegezhou_hot/archive/2010/12/04/1896471.html
定义:是一种创建型设计模式,它通过复制一个已经存在的实例来返回新的实例,而不是新建实例.被复制的实例就是我们所称的原型,这个原型是可定制的.
重点:
1、原型模式主要用于对象的复制,Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节。
2、使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显
应用场景:原型模式多用于创建复杂的或者耗时的实例, 因为这种情况下,复制一个已经存在的实例可以使程序运行更高效,或者创建值相等,只是命名不一样的同类数据.
类图:
JDK中的体现:
Object.clone;Cloneable
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