设计模式系列篇(四)——原型模式
2020-08-21 本文已影响0人
复旦猿
What
如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段都相同),在这种情况下,我们可以利用对已有对象(原型)进行复制(或者叫拷贝)的方式来创建新对象,以达到节省创建时间的目的。这种基于原型来创建对象的方式就叫作原型设计模式(Prototype Design Pattern),简称原型模式。
Why
对于大对象来说,使用原型模式可以无须从零开始构建一个新对象,直接利用已经构建好的对象进行复制或拷贝的方式创建,达到节省时间的目的。
How
原型模式有两种实现方法,深拷贝和浅拷贝。浅拷贝只会复制对象中基本数据类型数据和引用对象的内存地址,不会递归地复制引用对象,以及引用对象的引用对象……而深拷贝得到的是一份完完全全独立的对象。所以,深拷贝比起浅拷贝来说,更加耗时,更加耗内存空间。如果要拷贝的对象是不可变对象,浅拷贝共享不可变对象是没问题的,但对于可变对象来说,浅拷贝得到的对象和原始对象会共享部分数据,就有可能出现数据被修改的风险,也就变得复杂多了。这种情况下比较推荐使用浅拷贝,否则,没有充分的理由,不要为了一点点的性能提升而使用浅拷贝。
今天,我用《西游记》种齐天大圣孙悟空吹毛变猴的例子来向大家展示原型模式的两种实现方式。
浅拷贝
public class GoldenHoop {
private Double height;
private Double weight;
public GoldenHoop(Double height, Double weight) {
this.height = height;
this.weight = weight;
}
}
public class MonkeyKing implements Cloneable{
private Long id;
private Double height;
private Double weight;
private GoldenHoop goldenHoop;
public Long getId() {
return id;
}
public Double getHeight() {
return height;
}
public Double getWeight() {
return weight;
}
public GoldenHoop getGoldenHoop() {
return goldenHoop;
}
public MonkeyKing(Double height, Double weight, GoldenHoop goldenHoop) {
this.id = 0L;
this.height = height;
this.weight = weight;
this.goldenHoop = goldenHoop;
}
public MonkeyKing clone(Long id) {
MonkeyKing monkeyKing = null;
try {
monkeyKing = (MonkeyKing) super.clone();
monkeyKing.id = id;
} catch (Exception e) {
e.printStackTrace();
}
return monkeyKing;
}
}
浅拷贝方式,直接使用java的
java.lang.Object
中的clone
方法,返回一个新对象。但这里有个问题就是,猴子猴孙的金箍棒确是同一个,这个是不符合预期的,所以,浅拷贝的问题就暴漏出来了,即浅拷贝只能复制基本数据类型,对于引用类型其实指向的是同一个地址空间。
深拷贝
深拷贝可以借助序列化和反序列化实现。
public class GoldenHoop implements Serializable {
private Double height;
private Double weight;
public GoldenHoop(Double height, Double weight) {
this.height = height;
this.weight = weight;
}
}
public class MonkeyKing implements Cloneable, Serializable {
private Long id;
private Double height;
private Double weight;
private GoldenHoop goldenHoop;
public Long getId() {
return id;
}
public Double getHeight() {
return height;
}
public Double getWeight() {
return weight;
}
public GoldenHoop getGoldenHoop() {
return goldenHoop;
}
public MonkeyKing(Double height, Double weight, GoldenHoop goldenHoop) {
this.id = 0L;
this.height = height;
this.weight = weight;
this.goldenHoop = goldenHoop;
}
public MonkeyKing deepClone(Long id) throws IOException, ClassNotFoundException {
// write the object to stream
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// read the object from stream
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
MonkeyKing monkeyKing = (MonkeyKing) ois.readObject();
monkeyKing.id = id;
return monkeyKing;
}
}
测试类:
public class TestMain {
public static void main(String[] args) throws IOException, ClassNotFoundException {
GoldenHoop goldenHoop = new GoldenHoop(6D, 135000D);
MonkeyKing monkeyKing = new MonkeyKing(1.2D, 100D, goldenHoop);
for (long i = 0; i < 3L; i++){
MonkeyKing monkeySons = monkeyKing.clone(i);
System.out.println(monkeySons);
System.out.println(monkeySons.getGoldenHoop());
System.out.println();
}
for (long i = 0; i < 3L; i++){
MonkeyKing monkeySons = monkeyKing.deepClone(i);
System.out.println(monkeySons);
System.out.println(monkeySons.getGoldenHoop());
System.out.println();
}
}
}
结果为:
prototype.MonkeyKing@61bbe9ba
prototype.GoldenHoop@610455d6
prototype.MonkeyKing@511d50c0
prototype.GoldenHoop@610455d6
prototype.MonkeyKing@60e53b93
prototype.GoldenHoop@610455d6
prototype.MonkeyKing@7cd84586
prototype.GoldenHoop@30dae81
prototype.MonkeyKing@1b2c6ec2
prototype.GoldenHoop@4edde6e5
prototype.MonkeyKing@70177ecd
prototype.GoldenHoop@1e80bfe8
代码地址
写在最后
如果你觉得我写的文章帮到了你,欢迎点赞、评论、分享、赞赏哦,你们的鼓励是我不断创作的动力~