1、什么是原型模式
原型模式就是将一个已有的实例对象,将其复制出一个一模一样的实例对象出来,也就是克隆,原型模式算是设计模式中最简单的一个。它的核心就是类图中的Prototype类,实现原型模式非常简单,只需要两步,第一是实现Cloneable这一个接口,这个接口与Serializable(序列化)一样,是一个标识性接口,接口内部没有任何的内容,这个接口的作用就是通知jvm,可以在实现了这个接口的类上使用clone方法,复制一个一样的实例,如果一个接口没有实现Cloneable这个接口,直接去调用Object类中的clone()方法,就是抛出CloneNotSupportedException的异常。第二就是在类重写Object类中的clone方法,这个方法的方法体一般就只有一条语句:super.clone(),就是将克隆的工作让父类去完成,一般不会直接克隆一个实现Cloenable接口的类,而间接去使用它的子类,去完成克隆。Object类中的clone方法的原型是protected native Object clone() throws CloneNotSupportedException;也就是调用调用本地的c/c++代码去实现克隆。
2、原型模式的java实现
2.1Prototype类
public class Prototype implements Cloneable {
public Prototype() {
System.out.println("Prototype 构造");
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
2.2ConcetePrototype类
public class ConcetePrototype extends Prototype {
public ConcetePrototype() {
System.out.println("ConcetePrototype 构造");
}
public void show(){
System.out.println(this);
}
}
2.3Client类
public class client {
public static void main(String[] args) throws CloneNotSupportedException {
ConcetePrototype cp = new ConcetePrototype();
cp.show();
for (int i = 0; i < 10; i++) {
ConcetePrototype clone1 = (ConcetePrototype) cp.clone();
clone1.show();
}
}
}
在本地控制台打印的结果为:
Prototype 构造
ConcetePrototype 构造
ConcetePrototype@152b6651
ConcetePrototype@544a5ab2
ConcetePrototype@5d888759
ConcetePrototype@2e6e1408
ConcetePrototype@3ce53108
ConcetePrototype@6af62373
ConcetePrototype@459189e1
ConcetePrototype@55f33675
ConcetePrototype@527c6768
ConcetePrototype@65690726
ConcetePrototype@525483cd
这说明在进行克隆的过程中是不会去调用被克隆类的构造函数的,最开始的两个构造是一开台创建一个ConcetePrototyoe而调用的。克隆不是去创建(new)一个新对象,而是交由jvm调用本地方法,直接使用类的字节码去复制出一个新的对象。
3、原型模式的应用场景
使用原型模式去克隆一个对象比使用new关键字去创建一个对象性能要高,因为克隆是调用本地c/c++代码,直接对内存的二进制数据进行操作,所以当创建的实例比较大时,使用克隆比new要好,当要反复的创建同一种类对象时,就可以考虑采用原型模式以提高程序的性能。
4、深拷贝与浅拷贝
在java体系中,调用clone()方法是不会c克隆List、Set等数组或容器对象,只会去克隆8种基本类型(byte,char,short,int,float,double,long,boolean)和一个String类型。在Prototype类中新增一个LinkedList对象,克隆了3个对象,打印这个3个对象中的List的hashcode值,发现是一个样,但3个对象的地址是不一样的,说明,这个默认的浅拷贝,类内部的引用对象是不会被拷贝的,如果将这些引用对象也进行拷贝,这就是深拷贝。LinkedList这个类本身也实现了Cloneable接口,所以在对整个类克隆时,对重写的clone()方法做如下改动
import java.util.LinkedList;
public class Prototype implements Cloneable {
protected LinkedList list = new LinkedList();
public Prototype() {
System.out.println("Prototype 构造");
}
@Override
protected Prototype clone() throws CloneNotSupportedException {
Prototype prototype=(Prototype) super.clone();
prototype.list=(LinkedList) list.clone();
return prototype;
}
}
5、原型模式注意事项
5.1克隆不会去调用构造函数
5.2克隆有深拷贝与浅拷贝之分
5.3原型模式与单例模式是冲突的