原型模式
原型模式属于对象的创建模式,通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象,这就是原型模式的用意。
原型模式结构
原型模式要求对象实现一个可以克隆机身的接口(关于克隆,请参考Cloneable接口和Object的clone()方法),这样就可以通过复制一个实例对象本身来创建一个新的实例。这样一来,通过原型实例创建新的对象,就不再需要关心这个实例本身的类型,只要实现了克隆自身的方法,就可以通过这个方法来获取新的对象,而无须再通过new去创建。
原型模式涉及到三个角色:
1、客户角色
客户类提出创建对象的请求
2、抽象原型角色
这是一个抽象角色,通常由一个接口或者抽象类实现,此角色给出所有具体原型类所需的接口
3、具体原型角色
被复制的角色,此角色需要实现抽象的原型角色所要求的接口
原型模式示例
定义一个抽象原型角色,抽象类,实现Cloneable接口:
public abstract class Prototype implements Cloneable { public Prototype clone() { Prototype prototype = null; try { prototype = (Prototype)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return prototype; } public abstract void show(); }
定义一个具体原型角色,继承Prototype类:
public class ConcretePrototype extends Prototype { public void show() { System.out.println("ConcretePrototype.show()"); } }
定义一个客户端调用:
public class Client { public static void main(String[] args) { ConcretePrototype cp = new ConcretePrototype(); for (int i = 0; i < 10; i++) { ConcretePrototype clonecp = (ConcretePrototype)cp.clone(); clonecp.show(); } } }
比方说一个类实例很有用的时候,就可以使用原型模式去复制它。不过原型模式单独用得不多,一般是和其他设计模式一起使用。
原型模式在Java中的应用及解读
既然原型模式的关注点是在于通过克隆自身来获取一个和自身一样的对象,那其实只要是实现了Cloneable接口的类都可以算是原型模式的应用,比如ArrayList吧:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { ... public Object clone() { try { ArrayList<E> v = (ArrayList<E>) super.clone(); v.elementData = Arrays.copyOf(elementData, size); v.modCount = 0; return v; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(); } } ... }
程序中获取到了一个ArrayList的实例arrayList,我们完全可以通过调用arrayList.clone()方法获取到原ArrayList的拷贝。
原型模式的优点
原型模式是一种类的创建模式,可以看到到目前为止的四种创建型模式,客户端(调用方)都没有直接new一个类实例出来。把new一个类实例的动作由客户端(调用方)交给别人做而不是自己做,这就是创建型模式的宗旨。
使用原型模式创建对象比直接new一个对象在性能上好得多,因为Object类的clone()方法是一个native方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。
使用原型模式的另一个好处是简化对象的创建,使得创建对象就像普通的复制黏贴一样简单。