原型(Prototype)设计模式 1.0.0:什么是原型? ????用一个已经创建的对象,通过复制的手段创建一个和原对象相同或者相似的对象。 2.0.0:为什么要用原型? 对象创建的时间消耗要大于克隆
原型(Prototype)设计模式
1.0.0:什么是原型?
????用一个已经创建的对象,通过复制的手段创建一个和原对象相同或者相似的对象。
2.0.0:为什么要用原型?
- 对象创建的时间消耗要大于克隆(clone)的消耗?reason?
- 对象创建的时候是一个初始态,克隆是一个瞬时态。比如就是,你需要创建一个person,new 的话,person是一个初始态 A,你可能对person进行修改(update),修改之后person的状态发生了改变为 B。那么如果进行克隆的话,你的状态会停留在当前的状态。这就是clone和new的区别。在不同情况,可以分别处理。
- clone会保留对象的状态信息,数据和原对象是一致的,如果对象中含有引用类型的数据的话,那么他的指向地址是一样的,那么比如说有对象A和他的克隆者B。A对他的引用类型进行修改,同时也会影响到B。
eg:A对象有一只鸡,他把鸡杀了,鸡处于死亡状态,那么他的克隆对象的鸡也会死亡。哈哈哈,在某些时候,我们不想他们一样,那么就是需要重新创建新的鸡的引用,存放在堆内存中的数据也就是不同的。如何做?
num 对象的深复制 - 序列化方式--> 序列化 --> 反序列化
- 手动方式--> 所有的引用对象都实现cloneable --> 很麻烦,而且有一些基础类也没有实现cloneable
num 引用的重新创建和指定,引用比较多的时候,会比较麻烦
3.0.0原型的实现代码
3.1.0 浅克隆
@Setter @Getter @Slf4j public class ProtoType implements Cloneable { private int id; private String name; private Attribute attribute; @Override public String toString() { return "ProtoType(" + this.hashCode() + "){" + "id=" + id + ", name='" + name + '\'' + name.hashCode() + ", attribute=" + attribute + '}'; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Setter @Getter protected class Attribute { private int level; private String love; @Override public String toString() { return "Attribute(" + this.hashCode() + "){" + "level=" + level + ", love='" + love + '\'' + love.hashCode() + '}'; } } }
@Slf4j public class ProtoTypeTest { public static void main(String[] args) { ProtoType protoType = new ProtoType(); protoType.setId(1); protoType.setName("alice"); ProtoType.Attribute attribute = protoType.new Attribute(); attribute.setLevel(1); attribute.setLove("[email protected]"); protoType.setAttribute(attribute); log.info("protoType {}", protoType); try { Object clone = protoType.clone(); log.info("clone {}", clone); } catch (CloneNotSupportedException e) { e.printStackTrace(); } //run 001 //protoType ProtoType(752848266){id=1, name='alice'92903040, attribute=Attribute(815033865){level=1, love='[email protected]'-1847814268}} //clone ProtoType(340870931){id=1, name='alice'92903040, attribute=Attribute(815033865){level=1, love='[email protected]'-1847814268}} //run 002 //protoType ProtoType(752848266){id=1, name='alice'92903040, attribute=Attribute(815033865){level=1, love='[email protected]'-1847814268}} //clone ProtoType(340870931){id=1, name='alice'92903040, attribute=Attribute(815033865){level=1, love='[email protected]'-1847814268}} //run 003 //protoType ProtoType(752848266){id=1, name='alice'92903040, attribute=Attribute(815033865){level=1, love='[email protected]'-1847814268}} //clone ProtoType(340870931){id=1, name='alice'92903040, attribute=Attribute(815033865){level=1, love='[email protected]'-1847814268}} } }
3.2.0 深克隆
3.2.1 序列化深克隆
@Setter @Getter @Slf4j public class ProtoType implements Cloneable, Serializable { private int id; private String name; private Attribute attribute; @Override public String toString() { int i = this.hashCode(); log.info("----{}", System.identityHashCode(this)); return "ProtoType(" + this.hashCode() + "|||" + System.identityHashCode(this) + "){" + "id=" + id + ", name='" + name + '\'' + name.hashCode() + ", attribute=" + attribute + '}'; } @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } public Object deepClone() throws IOException, ClassNotFoundException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(this); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); return ois.readObject(); } @Setter @Getter protected class Attribute implements Serializable { private int level; private String love; @Override public String toString() { int i = this.hashCode(); return "Attribute(" + this.hashCode() + "|||" + System.identityHashCode(this) + "){" + "level=" + level + ", love='" + love + '\'' + love.hashCode() + '}'; } } }
@Slf4j public class ProtoTypeDeepTest { public static void main(String[] args) { ProtoType protoType = new ProtoType(); protoType.setId(1); protoType.setName("alice"); ProtoType.Attribute attribute = protoType.new Attribute(); attribute.setLevel(1); attribute.setLove("[email protected]"); protoType.setAttribute(attribute); log.info("protoType {}", protoType); ProtoType p2 = new ProtoType(); try { Object clone = protoType.deepClone(); log.info("clone {}", clone); } catch (Exception e) { e.printStackTrace(); } /**run1 protoType ProtoType(752848266){id=1, name='alice'92903040, attribute=Attribute(815033865){level=1, love='[email protected]'-1847814268}} clone ProtoType(359023572){id=1, name='alice'92903040, attribute=Attribute(305808283){level=1, love='[email protected]'-1847814268}} */ /** run2 protoType ProtoType(752848266){id=1, name='alice'92903040, attribute=Attribute(815033865){level=1, love='[email protected]'-1847814268}} clone ProtoType(359023572){id=1, name='alice'92903040, attribute=Attribute(305808283){level=1, love='[email protected]'-1847814268}} */ /** run3 protoType ProtoType(752848266){id=1, name='alice'92903040, attribute=Attribute(815033865){level=1, love='[email protected]'-1847814268}} clone ProtoType(359023572){id=1, name='alice'92903040, attribute=Attribute(305808283){level=1, love='[email protected]'-1847814268}} */ /** run4 增加 ProtoType p2 = new ProtoType()之后 内存地址也一样 protoType ProtoType(752848266){id=1, name='alice'92903040, attribute=Attribute(815033865){level=1, love='[email protected]'-1847814268}} clone ProtoType(359023572){id=1, name='alice'92903040, attribute=Attribute(305808283){level=1, love='[email protected]'-1847814268}} */ //涉及到的一点 内存的分配规则 } }
3.2.2 手动深克隆
@Setter @Getter @Slf4j public class ProtoType implements Cloneable { private int id; private String name; private Attribute attribute; @Override public Object clone() throws CloneNotSupportedException { ProtoType clone = (ProtoType) super.clone(); clone.setAttribute(attribute.clone()); return clone; } public Object deepClone() throws IOException, ClassNotFoundException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(this); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); return ois.readObject(); } @Override public String toString() { return "ProtoType(" + this.hashCode() + "|||" + System.identityHashCode(this) + "){" + "id=" + id + ", name='" + name + '\'' + name.hashCode() + ", attribute=" + attribute + '}'; } @Setter @Getter protected class Attribute implements Cloneable { private int level; private String love; @Override protected Attribute clone() throws CloneNotSupportedException { return (Attribute) super.clone(); } @Override public String toString() { return "Attribute(" + this.hashCode() + "|||" + System.identityHashCode(this) + "){" + "level=" + level + ", love='" + love + '\'' + love.hashCode() + '}'; } } } @Slf4j public class ProtoTypeDeepTest2 { public static void main(String[] args) { ProtoType protoType = new ProtoType(); protoType.setId(1); protoType.setName("alice"); ProtoType.Attribute attribute = protoType.new Attribute(); attribute.setLevel(1); attribute.setLove("[email protected]"); protoType.setAttribute(attribute); log.info("protoType {}", protoType); try { Object clone = protoType.clone(); log.info("clone {}", clone); } catch (Exception e) { e.printStackTrace(); } /** *protoType ProtoType(752848266|||752848266){id=1, name='alice'92903040, attribute=Attribute(815033865|||815033865){level=1, love='[email protected]'-1847814268}} *clone ProtoType(340870931|||340870931){id=1, name='alice'92903040, attribute=Attribute(1768305536|||1768305536){level=1, love='[email protected]'-1847814268}} * *protoType ProtoType(752848266|||752848266){id=1, name='alice'92903040, attribute=Attribute(815033865|||815033865){level=1, love='[email protected]'-1847814268}} *clone ProtoType(340870931|||340870931){id=1, name='alice'92903040, attribute=Attribute(1768305536|||1768305536){level=1, love='[email protected]'-1847814268}} */ } }