赞
踩
用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。
(1)Java 自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良。
(2)可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,
简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。
(1)需要为每一个类都配置一个 clone 方法
(2)clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。
当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,
每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。因此,深克隆、浅克隆需要运用得当。
原型模式的克隆分为浅克隆和深克隆。
(1)浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
(2)深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
(1)对象之间相同或相似,即只是个别的几个属性不同的时候。
(2)创建对象成本较大,例如初始化时间长,占用CPU太多,或者占用网络资源太多等,需要优化资源。
(3)创建一个对象需要繁琐的数据准备或访问权限等,需要提高性能或者提高安全性。
(4)系统中大量使用该类对象,且各个调用者都需要给它的属性重新赋值。
package prototype; /** * TODO * * @author lyq * @version 1.0 * @date 2021/7/9 11:55 */ public class Pension implements Cloneable { String name; String avg; public Pension(String name, String avg) { this.name = name; this.avg = avg; } @Override public Pension clone() throws CloneNotSupportedException { return (Pension) super.clone(); } public String getName() { return name; } public String getAvg() { return avg; } }
package prototype; /** * 浅克隆 * * @author lyq * @version 1.0 * @date 2021/7/9 11:14 */ public class ShallowClone implements Cloneable { String name; Pension pension; public ShallowClone() { System.out.println("开始运行:"); } @Override public ShallowClone clone() throws CloneNotSupportedException { System.out.println("进行复制name"); return (ShallowClone) super.clone(); } public void setName(String name) { this.name = name; } public String getName() { return name; } public Pension getPension() { return pension; } public void setPension(Pension pension) { this.pension = pension; } public static void main(String[] args) throws CloneNotSupportedException { ShallowClone sc1 = new ShallowClone(); sc1.setName("张三"); Pension pen = new Pension("小骨头", "18"); sc1.setPension(pen); ShallowClone sc2 = sc1.clone(); //这里使用==,判断是不是指向同一个内存空间,打印结果是true System.out.println("name属性内存空间:" + (sc1.getName() == sc2.getName())); System.out.println("pension对象内存空间:" + (sc1.getPension() == sc2.getPension())); System.out.println("sc1 == sc2 ? :" + (sc1 == sc2)); System.out.println("sc1:" + sc1.getName()); System.out.println("sc2:" + sc2.getName()); System.out.println("sc1:name = " + sc1.getPension().getName() + ",avg = " + sc1.getPension().getAvg()); System.out.println("sc2:name = " + sc2.getPension().getName() + ",avg = " + sc2.getPension().getAvg()); } }
结果
开始运行:
进行复制name
name属性内存空间:true
pension对象内存空间:true
sc1 == sc2 ? :false
sc1:张三
sc2:张三
sc1:name = 小骨头,avg = 18
sc2:name = 小骨头,avg = 18
可以看到,在ShallowClone.class类中的clone()方法中未对Pension对象进行克隆,所以得出的结果是sc2的Pension对象的地址还是sc1的
package prototype; /** * 深克隆 * * @author lyq * @version 1.0 * @date 2021/7/9 11:19 */ public class DeepClone implements Cloneable{ String name; Pension pension; public void setName(String name) { this.name = name; } public String getName() { return name; } public Pension getPension() { return pension; } public void setPension(Pension pension) { this.pension = pension; } @Override public DeepClone clone() throws CloneNotSupportedException { System.out.println("复制成功!"); DeepClone deep = (DeepClone) super.clone(); deep.setPension(deep.getPension().clone()); return deep; } public static void main(String[] args) throws CloneNotSupportedException { DeepClone dc1 = new DeepClone(); dc1.setName("张三"); Pension per = new Pension("小骨头", "18"); dc1.setPension(per); DeepClone dc2 = dc1.clone(); //属性结果true System.out.println("name属性内存空间:" + (dc1.getName() == dc2.getName())); //对象结果false System.out.println("pension对象内存空间:" + (dc1.getPension() == dc2.getPension())); System.out.println("dc1 == dc2 ? :" + (dc1 == dc2)); System.out.println("dc1:" + dc1.getName()); System.out.println("dc2:" + dc2.getName()); System.out.println("dc1:name = " + dc1.getPension().getName() + ",avg = " + dc1.getPension().getAvg()); System.out.println("dc2:name = " + dc2.getPension().getName() + ",avg = " + dc2.getPension().getAvg()); } }
结果
复制成功!
name属性内存空间:true
pension对象内存空间:false
dc1 == dc2 ? :false
dc1:张三
dc2:张三
dc1:name = 小骨头,avg = 18
dc2:name = 小骨头,avg = 18
可以看到,DeepClone.class类的clone()方法中,对Pension对象也进行了克隆,所以dc2的Pension对象的内存地址和dc1的不相同。但是这里的DeepClone的name属性的内存地址是一样的。
参考了C语言中文网的原型模式:http://c.biancheng.net/view/1343.html
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。