原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。

场景

  • 类初始化需要消耗非常多的资源
  • 通过new 产生一个对象需要非常繁琐的数据准备或权限访问
  • 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改起值

实现

原型模式的本质就是对象拷贝,实现基于对象Clone,此处不做过多描述。

浅拷贝

浅拷贝(浅复制、浅克隆):被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象。
 
创建Child类

  1. public class Child implements Cloneable {
  2. public String name;
  3. public int age;
  4. public Child(String name, int age) {
  5. this.name = name;
  6. this.age = age;
  7. }
  8. @Override
  9. protected Object clone() throws CloneNotSupportedException {
  10. return super.clone();
  11. }
  12. }

创建Father类,浅拷贝

  1. public class Father implements Cloneable {
  2. public String name;
  3. public int age;
  4. public Child child;
  5. public Father(String name, int age, Child child) {
  6. this.name = name;
  7. this.age = age;
  8. this.child = child;
  9. }
  10. @Override
  11. protected Object clone() {
  12. try {
  13. return super.clone()
  14. } catch (CloneNotSupportedException e) {
  15. e.printStackTrace();
  16. }
  17. return null;
  18. }
  19. @Override
  20. public String toString() {
  21. return "name:" + name + ", age:" + age + ", Child name:" + child.name + ", Child age" + child.age +
  22. ", hashcode : " + hashCode() + ", Child hashcode:" + child.hashCode();
  23. }
  24. }

浅拷贝示例

  1. public class SimpleClone {
  2. public static void main(String[] args) {
  3. Child child = new Child("小张三", 10);
  4. Father fatherA = new Father("张三", 30, child);
  5. System.out.println("clone前 fatherA:" + fatherA.toString());
  6. Father fatherB = (Father) fatherA.clone();
  7. System.out.println("clone后 fatherA:" + fatherA.toString());
  8. System.out.println("clone后 fatherB:" + fatherB.toString());
  9. fatherB.name = "李四";
  10. fatherB.age = 40;
  11. fatherB.child.name = "小李四";
  12. fatherB.child.age = 15;
  13. System.out.println("clone后修改信息 fatherA:" + fatherA.toString());
  14. System.out.println("clone后修改信息 fatherB:" + fatherB.toString());
  15. }
  16. }

输出结果

  1. clone fatherAname:张三, age:30, Child name:小张三, Child age10, hashcode : 1627674070, Child hashcode:1360875712
  2. clone fatherAname:张三, age:30, Child name:小张三, Child age10, hashcode : 1627674070, Child hashcode:1360875712
  3. clone fatherBname:张三, age:30, Child name:小张三, Child age10, hashcode : 1625635731, Child hashcode:1360875712
  4. clone后修改信息 fatherAname:张三, age:30, Child name:小李四, Child age15, hashcode : 1627674070, Child hashcode:1360875712
  5. clone后修改信息 fatherBname:李四, age:40, Child name:小李四, Child age15, hashcode : 1625635731, Child hashcode:1360875712

从最后对 child 的输出可以看到,A 和 B 的 child 对象,实际上还是指向了统一个对象,只对对它的引用进行了传递

深拷贝

深拷贝(深复制、深克隆):被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。深拷贝把要复制的对象所引用的对象都复制了一遍。

创建Father类,深拷贝

  1. public class Father implements Cloneable {
  2. public String name;
  3. public int age;
  4. public Child child;
  5. public Father(String name, int age, Child child) {
  6. this.name = name;
  7. this.age = age;
  8. this.child = child;
  9. }
  10. @Override
  11. protected Object clone() {
  12. try {
  13. Father father = (Father) super.clone();
  14. father.child = (Child) this.child.clone();
  15. return father;
  16. } catch (CloneNotSupportedException e) {
  17. e.printStackTrace();
  18. }
  19. return null;
  20. }
  21. @Override
  22. public String toString() {
  23. return "name:" + name + ", age:" + age + ", Child name:" + child.name + ", Child age" + child.age +
  24. ", hashcode : " + hashCode() + ", Child hashcode:" + child.hashCode();
  25. }
  26. }

深拷贝示例

  1. public class DeepClone {
  2. public static void main(String[] args) {
  3. Child child = new Child("小张三", 10);
  4. Father fatherA = new Father("张三", 30, child);
  5. System.out.println("clone前 fatherA:" + fatherA.toString());
  6. Father fatherB = (Father) fatherA.clone();
  7. System.out.println("clone后 fatherA:" + fatherA.toString());
  8. System.out.println("clone后 fatherB:" + fatherB.toString());
  9. fatherB.name = "李四";
  10. fatherB.age = 40;
  11. fatherB.child.name = "小李四";
  12. fatherB.child.age = 15;
  13. System.out.println("clone后修改信息 fatherA:" + fatherA.toString());
  14. System.out.println("clone后修改信息 fatherB:" + fatherB.toString());
  15. }
  16. }

输出结果

  1. clone fatherAname:张三, age:30, Child name:小张三, Child age10, hashcode : 1627674070, Child hashcode:1360875712
  2. clone fatherAname:张三, age:30, Child name:小张三, Child age10, hashcode : 1627674070, Child hashcode:1360875712
  3. clone fatherBname:张三, age:30, Child name:小张三, Child age10, hashcode : 1625635731, Child hashcode:1580066828
  4. clone后修改信息 fatherAname:张三, age:30, Child name:小张三, Child age10, hashcode : 1627674070, Child hashcode:1360875712
  5. clone后修改信息 fatherBname:李四, age:40, Child name:小李四, Child age15, hashcode : 1625635731, Child hashcode:1580066828

优点

  • 原型模式是在内存中二进制流的拷贝,要比new一个对象的性能要好,特别是需要产生大量对象时。

缺点

  • 直接在内存中拷贝,构造函数是不会执行的,这样就减少了约束,这既是优点也是缺点

Android 中的应用

  • 对象Clone()的实现

参考

书籍:《设计模式之禅》、《Android源码设计模式》
技术文章:菜鸟教程-设计模式