原型模式
1.模式动机与定义
模式动机
- 复制一个对象,从而克隆出多个与原型对象一模一样的对象--原型模式
- 有些对象的创建过程较为复杂,而且需要频繁创建
- 通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象
模式定义
- 原型模式(Prototype Pattern):原型模式是一种对象创建型模式,用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象
- 原型模式允许通过一个原型对象创建一个或多个同类型的其他对象,而无须知道任何创建的细节
2.模式结构与分析
模式结构
原型模式包含如下角色:
- Prototype:抽象原型类:是定义具有克隆自己的方法的接口,是所有具体原型类的公共父类,可以是抽象类,也可以是接口
- ConcretePrototype:具体原型类:具体原型类实现具体的克隆方法,在克隆方法中返回自己的一个克隆对象
- Client:客户类:客户类让一个原型克隆自身,从而创建一个新的对象。在客户类中,只需要直接实例化或通过工厂方法等方式创建一个对象,再通过调用该对象的克隆方法复制得到多个相同的对象。
模式分析
- 所有的Java类都继承自java.lang.Object,而Object类提供一个clone()方法,可以将一个Java对象复制一份
- 在Java中可以直接使用Obiect提供的clone()方法来实现对象的克隆(浅克隆)
- 能够实现克隆的Java类必须实现一个标识接口Cloneable,表示这个Java类支持复制
- 如果一个类没有实现这个接口但是调用了clone()方法,Java编译器将抛出一个CloneNotSupportedException异常
//Java内置的克隆方法,浅克隆
public class PrototypeDemo implements Cloneable{
public Object clone() //定义clone方法
{
Object object = null;
try{
object= super.clone0; //调用object的克隆方法
}catch (CloneNotSupportedException exception){
System.err.println("Not support cloneable");
}
return object;
}
}
通常情况下,一个类包含一些成员对象,在使用原型模式克隆对象时,根据其成员对象是否也克隆,原型模式可以分为两种形式:深克隆和浅克隆
- 浅克隆(Shallow Clone):当原型对象被复制时,只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制,仅仅复制所考虑的对象,而不复制它所引用的成员对象。也就是其中的成员对象并不复制。
- 深克隆(Deep Clone):除了对象本身被复制外,对象所包含的所有成员变量也将被复制,深克隆想把要复制的对象所引用的对象都复制了一遍。
3.模式效果与应用
原型模式优点
- 简化对象的创建过程,通过复制一个已有实例可以提高新实例的创建效率
- 扩展性较好
- 简化创建结构,原型模式中产品的复制是通过封装在原型类中的克隆方法实现的,无须专门的工厂类来创建产品
- 可以使用深克隆的方式保存对象的状态,以便在需要的时候使用,可辅助实现撤销操作
原型模式缺点
- 需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的内部,当对已有的类进行改造时,需要修改源代码,违背了开闭原则
- 在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重的嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来可能会比较麻烦
使用情况
- 创建新对象成本较大,新对象可以通过复制已有对象来获得,如果是相似对象,则可以对其成员变量稍作修改
- 系统要保存对象的状态,而对象的状态变化很小
- 需要避免使用分层次的工厂类来创建分层次的对象
模式应用
- 原型模式应用于很多软件中,如果每次创建一个对象要花大量时间,原型模式是最好的解决方案。很多软件提供的复制(Ctrl +C)和粘贴(Ctrl + V)操作就是原型模式的应用,复制得到的对象与原型对象是两个类型相同但内存地址不同的对象,通过原型模式可以大大提高对象的创建效率。
- 在Struts2中为了保证线程的安全性,Action对象的创建使用了原型模式,访问一个已经存在的Action对象时将通过克隆的方式创建出一个新的对象,从而保证其中定义的变量无须进行加锁实现同步,每一个Action中都有自己的成员变量,避免Struts1因使用单例模式而导致的并发和同步问题。
- 在Spring中,用户也可以采用原型模式来创建新的bean实例,从而实现每次获取的是通过克隆生成的新实例,对其进行修改时对原有实例对象不造成任何影响
浙公网安备 33010602011771号