原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。
场景
- 类初始化需要消耗非常多的资源
- 通过new 产生一个对象需要非常繁琐的数据准备或权限访问
- 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改起值
实现
原型模式的本质就是对象拷贝,实现基于对象Clone,此处不做过多描述。
浅拷贝
浅拷贝(浅复制、浅克隆):被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象。
创建Child类
public class Child implements Cloneable {public String name;public int age;public Child(String name, int age) {this.name = name;this.age = age;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}}
创建Father类,浅拷贝
public class Father implements Cloneable {public String name;public int age;public Child child;public Father(String name, int age, Child child) {this.name = name;this.age = age;this.child = child;}@Overrideprotected Object clone() {try {return super.clone()} catch (CloneNotSupportedException e) {e.printStackTrace();}return null;}@Overridepublic String toString() {return "name:" + name + ", age:" + age + ", Child name:" + child.name + ", Child age" + child.age +", hashcode : " + hashCode() + ", Child hashcode:" + child.hashCode();}}
浅拷贝示例
public class SimpleClone {public static void main(String[] args) {Child child = new Child("小张三", 10);Father fatherA = new Father("张三", 30, child);System.out.println("clone前 fatherA:" + fatherA.toString());Father fatherB = (Father) fatherA.clone();System.out.println("clone后 fatherA:" + fatherA.toString());System.out.println("clone后 fatherB:" + fatherB.toString());fatherB.name = "李四";fatherB.age = 40;fatherB.child.name = "小李四";fatherB.child.age = 15;System.out.println("clone后修改信息 fatherA:" + fatherA.toString());System.out.println("clone后修改信息 fatherB:" + fatherB.toString());}}
输出结果
clone前 fatherA:name:张三, age:30, Child name:小张三, Child age10, hashcode : 1627674070, Child hashcode:1360875712clone后 fatherA:name:张三, age:30, Child name:小张三, Child age10, hashcode : 1627674070, Child hashcode:1360875712clone后 fatherB:name:张三, age:30, Child name:小张三, Child age10, hashcode : 1625635731, Child hashcode:1360875712clone后修改信息 fatherA:name:张三, age:30, Child name:小李四, Child age15, hashcode : 1627674070, Child hashcode:1360875712clone后修改信息 fatherB:name:李四, age:40, Child name:小李四, Child age15, hashcode : 1625635731, Child hashcode:1360875712
从最后对 child 的输出可以看到,A 和 B 的 child 对象,实际上还是指向了统一个对象,只对对它的引用进行了传递
深拷贝
深拷贝(深复制、深克隆):被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。深拷贝把要复制的对象所引用的对象都复制了一遍。
创建Father类,深拷贝
public class Father implements Cloneable {public String name;public int age;public Child child;public Father(String name, int age, Child child) {this.name = name;this.age = age;this.child = child;}@Overrideprotected Object clone() {try {Father father = (Father) super.clone();father.child = (Child) this.child.clone();return father;} catch (CloneNotSupportedException e) {e.printStackTrace();}return null;}@Overridepublic String toString() {return "name:" + name + ", age:" + age + ", Child name:" + child.name + ", Child age" + child.age +", hashcode : " + hashCode() + ", Child hashcode:" + child.hashCode();}}
深拷贝示例
public class DeepClone {public static void main(String[] args) {Child child = new Child("小张三", 10);Father fatherA = new Father("张三", 30, child);System.out.println("clone前 fatherA:" + fatherA.toString());Father fatherB = (Father) fatherA.clone();System.out.println("clone后 fatherA:" + fatherA.toString());System.out.println("clone后 fatherB:" + fatherB.toString());fatherB.name = "李四";fatherB.age = 40;fatherB.child.name = "小李四";fatherB.child.age = 15;System.out.println("clone后修改信息 fatherA:" + fatherA.toString());System.out.println("clone后修改信息 fatherB:" + fatherB.toString());}}
输出结果
clone前 fatherA:name:张三, age:30, Child name:小张三, Child age10, hashcode : 1627674070, Child hashcode:1360875712clone后 fatherA:name:张三, age:30, Child name:小张三, Child age10, hashcode : 1627674070, Child hashcode:1360875712clone后 fatherB:name:张三, age:30, Child name:小张三, Child age10, hashcode : 1625635731, Child hashcode:1580066828clone后修改信息 fatherA:name:张三, age:30, Child name:小张三, Child age10, hashcode : 1627674070, Child hashcode:1360875712clone后修改信息 fatherB:name:李四, age:40, Child name:小李四, Child age15, hashcode : 1625635731, Child hashcode:1580066828
优点
- 原型模式是在内存中二进制流的拷贝,要比new一个对象的性能要好,特别是需要产生大量对象时。
缺点
- 直接在内存中拷贝,构造函数是不会执行的,这样就减少了约束,这既是优点也是缺点
Android 中的应用
- 对象Clone()的实现
参考
书籍:《设计模式之禅》、《Android源码设计模式》
技术文章:菜鸟教程-设计模式
