参考:https://www.cnblogs.com/betterboyz/p/9356190.html
简介:
原型模式要求对象实现一个“克隆”本身的接口,这样就能够通过复制一个实例对象自身来创立一个新的实例。这样一来,通过原型实例创立新的对象,就不再须要关怀这个实例自身的类型,只有实现了克隆本身的办法,就能够通过这个办法来获取新的对象,而无须再去通过new来创立
模式类图:
Object: java中的Object类,提供了clone()办法
ConcreteObject1,ConcreteObject1:实现了克隆办法的具体类
应用场景:
实际上这个克隆跟new可能差不多,只不过new进去的对象,外面的属性都是默认值,如果须要产生大批量对象,并且这些对象的属性值大部分或者全都雷同的状况下,应用克隆,会比拟省事儿
模式实例:
public class Test { public static void main(String[] args) throws Exception { Person p1 = new Person(); Person p2 = (Person)p1.clone(); System.out.println("p1.loc == p2.loc? " + (p1.loc == p2.loc)); p1.loc.street.reverse(); System.out.println(p2.loc.street); p1.name = new String("alice"); System.out.println("p1.name:"+p1.name); System.out.println("p2.name:"+p2.name); }}class Person implements Cloneable { int age = 8; int score = 100; String name = new String("jack"); Location loc = new Location(new StringBuilder("bj"), 22); @Override public Object clone() throws CloneNotSupportedException { Person p = (Person)super.clone(); p.loc = (Location)loc.clone(); return p; }}class Location implements Cloneable { StringBuilder street; int roomNo; @Override public String toString() { return "Location{" + "street='" + street + ''' + ", roomNo=" + roomNo + '}'; } public Location(StringBuilder street, int roomNo) { this.street = street; this.roomNo = roomNo; } @Override public Object clone() throws CloneNotSupportedException { return super.clone(); }}
测试后果:
总结:此处有一个须要留神的中央,那就是如上代码中,Person类当中用一个援用是Location,那么在Person实现了clone办法之后,Location也须要实现clone办法,否则的话克隆进去的对象跟原对象的Location指向同一个援用,扭转其中的一个对象的Location,另一个也会跟着改,就比拟不合理;除此之外String属性也是属于援用类型,那么它会不会有这个问题呢,分两种状况来看,
第一:String name = "jack";
这种状况不存在,因为String自身是不可变的,并且它指向了常量池外面的一个常量,如果扭转String,只是将String的援用指向常量池外面的另一个常量,原来的那个常量并没有被扭转,原来的对象也不会被扭转
第二种 String name = new String("jack");
这种状况也不存在问题,如果p1.name = new String("jack"),将p1克隆出p2,改p2.name = "alice";或者p2.name = new String("alice"),第一种改法,将p2.name的援用间接指向了常量池,不会影响p1,第二种改法相当于new了一个新的String对象付给p2.name,也不会影响p1,所以String虽是援用类型,然而不会存在这个问题