什么是原型模式
定义:用原型实例指定创建对象的种类,并且通过复制原型实例创建新的对象。
我们都看过《西游记》,里面孙悟空拥有拔毛变分身的技能,只需要拔毛轻轻一吹就会变出许许多多的孙悟空。孙悟空本体就是原型实例,通过分身术复制变出新的孙悟空,分身孙悟空与本体孙悟空相对独立,即分身孙悟空遇到任何问题,都不会影响本体孙悟空。原型模式正是采用这种思想,用一个已经创建成功的对象实例作为原型,通过复制该原型实例来创建一个和原型实例相同或相似的新对象。
原型模式的应用场景
原型模式的优缺点
原型模式的优点如下:
原型模式的缺点如下:
原型模式的结构与实现
1、结构
原型模式的角色如下。
1.用户角色(Client):使用者调用具体原型对象中的 clone 方法完成对象的复制创建。
2.抽象原型角色(Prototype):继承了 Cloneable 接口,声明具备clone能力。
3.具体原型角色(ConcretePrototype):实现了 clone 方法。
2、实现
浅克隆的实现
public class ShallowCopyDemo implements Cloneable {
private String demoName;
private int demoInt;
private Helper helper = new Helper();
private List<String> demoList = new ArrayList<>();
public String getDemoName() {
return demoName;
}
public void setDemoName(String demoName) {
this.demoName = demoName;
}
public int getDemoInt() {
return demoInt;
}
public void setDemoInt(int demoInt) {
this.demoInt = demoInt;
}
public String getHelperName() {
return helper.getHelperName();
}
public void setHelperName(String helperName) {
this.helper.setHelperName(helperName);
}
public void addToDemoList(String demoName) {
demoList.add(demoName);
}
public void showDemoList() {
for(String s : this.demoList) {
System.out.println(s);
}
}
@Override
public String toString() {
return "ShallowCopyDemo [demoName=" + demoName + ", demoInt=" + demoInt + ", helperName=" + helper.getHelperName() + " ]";
}
@Override
protected ShallowCopyDemo clone() throws CloneNotSupportedException {
ShallowCopyDemo shallowCopyDemo = null;
try {
shallowCopyDemo = (ShallowCopyDemo) super.clone();
} catch (Exception e) {
return null;
}
return shallowCopyDemo;
}
}
public class Helper {
private String helperName;
public String getHelperName() {
return helperName;
}
public void setHelperName(String helperName) {
this.helperName = helperName;
}
}
public class ClientTest {
public static void main(String[] args) throws CloneNotSupportedException {
ShallowCopyDemo shallowCopyDemo = new ShallowCopyDemo();
shallowCopyDemo.setDemoInt(10);
shallowCopyDemo.setDemoName("IT界的泥石流");
shallowCopyDemo.addToDemoList("请关注公众号:IT界的泥石流");
shallowCopyDemo.setHelperName("非常感谢");
shallowCopyDemo.showDemoList();
System.out.println(shallowCopyDemo.toString());
ShallowCopyDemo shallowCopyDemo2 = shallowCopyDemo.clone();
shallowCopyDemo.setDemoInt(100);
shallowCopyDemo.setDemoName("祝工作顺利");
shallowCopyDemo2.addToDemoList("学习进步");
shallowCopyDemo2.setHelperName("谢谢支持");
shallowCopyDemo.showDemoList();
System.out.println(shallowCopyDemo.toString());
shallowCopyDemo2.showDemoList();
System.out.println(shallowCopyDemo2.toString());
}
}
执行结果:
请关注公众号:IT界的泥石流
ShallowCopyDemo [demoName=IT界的泥石流, demoInt=10, helperName=非常感谢 ]
请关注公众号:IT界的泥石流
学习进步
ShallowCopyDemo [demoName=祝工作顺利, demoInt=100, helperName=谢谢支持 ]
请关注公众号:IT界的泥石流
学习进步
ShallowCopyDemo [demoName=IT界的泥石流, demoInt=10, helperName=谢谢支持 ]
我们首先创建一个 ShallowCopyDemo 实例 shallowCopyDemo 对其赋值并输出结果,输出结果符合预期。接着我们使用 clone 方法复制出另一个实例 shallowCopyDemo2 对其赋值后,再次输出 shallowCopyDemo 和 shallowCopyDemo2 的结果,从输出结果看出第一个实例 shallowCopyDemo 的 demoList 和 helper 变量的值被修改了。
不是说好的复制出全新的一份吗?应该是相互独立的才对。这是因为 clone 方法在java中除了基本数据类型和String类型外,数组、集合引用和对象引用的成员变量都不会被拷贝,它们是多个克隆实例与本体共用那一部分数据的,这是浅克隆。
深克隆的实现
当我们希望克隆实例与本体相互独立时,应使用深克隆。
public class DeepCopyDemo implements Serializable {
private String demoName;
private int demoInt;
private Helper helper = new Helper();
private List<String> demoList = new ArrayList<>();
public String getDemoName() {
return demoName;
}
public void setDemoName(String demoName) {
this.demoName = demoName;
}
public int getDemoInt() {
return demoInt;
}
public void setDemoInt(int demoInt) {
this.demoInt = demoInt;
}
public String getHelperName() {
return helper.getHelperName();
}
public void setHelperName(String helperName) {
this.helper.setHelperName(helperName);
}
public void addToDemoList(String demoName) {
demoList.add(demoName);
}
public void showDemoList() {
for(String s : this.demoList) {
System.out.println(s);
}
}
@Override
public String toString() {
return "ShallowCopyDemo [demoName=" + demoName + ", demoInt=" + demoInt + ", helperName=" + helper.getHelperName() + " ]";
}
public DeepCopyDemo deepClone() throws IOException, ClassNotFoundException {
//将对象写到流里
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//从流里读回来
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (DeepCopyDemo) ois.readObject();
}
}
public class Helper implements Serializable {
private String helperName;
public String getHelperName() {
return helperName;
}
public void setHelperName(String helperName) {
this.helperName = helperName;
}
}
public class ClientTest {
public static void main(String[] args) throws ClassNotFoundException, IOException {
DeepCopyDemo deepCopyDemo = new DeepCopyDemo();
deepCopyDemo.setDemoInt(10);
deepCopyDemo.setDemoName("IT界的泥石流");
deepCopyDemo.addToDemoList("请关注公众号:IT界的泥石流");
deepCopyDemo.setHelperName("非常感谢");
deepCopyDemo.showDemoList();
System.out.println(deepCopyDemo.toString());
DeepCopyDemo deepCopyDemo2 = deepCopyDemo.deepClone();
deepCopyDemo2.setDemoInt(100);
deepCopyDemo2.setDemoName("祝工作顺利");
deepCopyDemo2.addToDemoList("学习进步");
deepCopyDemo2.setHelperName("谢谢支持");
deepCopyDemo.showDemoList();
System.out.println(deepCopyDemo.toString());
deepCopyDemo2.showDemoList();
System.out.println(deepCopyDemo2.toString());
}
}
执行结果:
请关注公众号:IT界的泥石流
ShallowCopyDemo [demoName=IT界的泥石流, demoInt=10, helperName=非常感谢 ]
请关注公众号:IT界的泥石流
ShallowCopyDemo [demoName=IT界的泥石流, demoInt=10, helperName=非常感谢 ]
请关注公众号:IT界的泥石流
学习进步
ShallowCopyDemo [demoName=祝工作顺利, demoInt=100, helperName=谢谢支持 ]
DeepCopyDemo 与 ShallowCopyDemo 差别在于 DeepCopyDemo 不实现 Cloneable 接口,而是实现 Serializable,并通过序列化与反序列化的方式完成对象复制。
我们从运行结果上可以看到克隆实例和本体互不影响。
以上就是今天《原型模式》的讲解,至此创建型模式已讲述完毕。良好的代码风格需要长期不断的积累学习。各位读者大人若有问题,欢迎后台留言,我将第一时间回复!
下期文章将介绍《设计模式(十二):代理模式》