定义
- Specify the kinds of objects to create using a prototypical instance,and create new objects by copying this prototype(用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象)
- 原型模式简单程度仅次于单例模式和迭代器模式,其核心是一个Clone方法,通过该方法进行对象的拷贝。
优点
使用场景
- 场景:
- 资源优化场景:类初始化需要消耗非常多的资源,这个资源包括数据、硬件资源等。
- 性能和安全要求的场景:通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
- 一个对象多个修改者的场景:一个对象需要提供给其他对象访问,而且各个调用者都可能需要修改其值时,可以使用原型模式拷贝多个对象给调用者调用。
- 利用原型模式先产生一个包含大量共有信息的类,然后可以拷贝出副本,修正细节信息,建立一个完整的个性对象。
代码
通用类图
基本的建造者模式
类图
没有,就一个类
代码
原型设计模式代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com.pattern;
import com.pattern.prototype.PrototypeClass; import org.junit.Test;
public class PrototypeTest { @Test public void PrototypeTest(){ PrototypeClass instance1 = new PrototypeClass(); try { PrototypeClass instance2 = instance1.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } }
|
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com.pattern;
import com.pattern.prototype.PrototypeClass; import org.junit.Test;
public class PrototypeTest { @Test public void PrototypeTest(){ PrototypeClass instance1 = new PrototypeClass(); try { PrototypeClass instance2 = instance1.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } }
|
结果
浅拷贝和深拷贝
代码
浅拷贝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.pattern.prototype;
import java.util.ArrayList;
public class ShallowCopy implements Cloneable { private ArrayList<String> arrayList = new ArrayList<>(); @Override public ShallowCopy clone(){ ShallowCopy shallowCopy = null; try { shallowCopy = (ShallowCopy) super.clone(); } catch (CloneNotSupportedException e){ e.printStackTrace(); } return shallowCopy; } public void addValue(String value){ this.arrayList.add(value); } public ArrayList<String> getArrayList(){ return this.arrayList; } }
|
测试代码
1 2 3 4 5 6 7 8
| @Test public void ShallowCopyTest(){ ShallowCopy instance1 = new ShallowCopy(); instance1.addValue("1"); ShallowCopy instance2 = instance1.clone(); instance2.addValue("2"); System.out.println(instance1.getArrayList()); }
|
运行结果
深拷贝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package com.pattern.prototype;
import java.util.ArrayList;
public class DeepCopy implements Cloneable { private ArrayList<String> arrayList = new ArrayList<>(); @Override public DeepCopy clone(){ DeepCopy deepCopy = null; try { deepCopy = (DeepCopy) super.clone(); deepCopy.arrayList = (ArrayList<String>) this.arrayList.clone(); } catch (CloneNotSupportedException e){ e.printStackTrace(); } return deepCopy; } public void addValue(String value){ this.arrayList.add(value); } public ArrayList<String> getArrayList(){ return this.arrayList; } }
|
测试代码
1 2 3 4 5 6 7 8
| @Test public void DeepCopyTest(){ DeepCopy instance1= new DeepCopy(); instance1.addValue("1"); DeepCopy instance2 = instance1.clone(); instance2.addValue("2"); System.out.println(instance1.getArrayList()); }
|
运行结果
我们发现,在浅拷贝的时候,改变instance2中arraylist的值导致instance1的值也改变了,而在深拷贝则没这样的情况。这是因为Java做了一个偷懒的动作。
Object类提供的方法Clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址,这就是浅拷贝。两个对象共享了一个私有变量。这是一种非常不安全的,至于String类为什么也会被拷贝。请自行网上查阅资料。
注意
- 原型模式的构造函数不会被执行,Object类的clone方法是从内存中(堆内存)以二进制流的方式进行拷贝,重新分配一个内存块。
- 浅拷贝和深拷贝
- 原型模式,引用的成员变量必须满足两个条件才会被拷贝:一是类的成员变量,而不是方法内变量;二是必须是一个可变的引用对象,而不是一个原始类型或不可变对象
- 深拷贝和浅拷贝不建议混合使用,特别是涉及到类的继承时,父类有多个引用的情况就非常复杂,建议方案是浅拷贝和深拷贝分开实现