参考: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虽是引用类型,但是不会存在这个问题
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。