在之前的几篇博文已经介绍了只创建一个实例的单例模式( Singleton ),以及一步步创建复杂对象的建造者模式( Builder )。本文继续来介绍创建型模式的另外一个:原型模式,原型模式(Prototype Pattern)是一种创建型设计模式,它允许通过复制现有对象来创建新对象,而不是使用显式的构造函数来创建新对象。
接下来,我们主要从如下几个方面来进行讲解。
原型模式是一种创建型模式。通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的方法创建出更多同类型的对象。
意图
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
结构
原型模式的基本结构如下:
这里涉及的参与者有如下几种:
在Java中,可以使用clone()方法来实现原型模式。
为什么要使用Clone呢?
在Java中,使用clone()方法可以创建一个新的对象副本,对它进行修改不会影响原始对象。在某些情况下,使用clone()方法可以比创建新的对象更快。这是因为clone()方法不需要调用构造函数。在某些情况下,构造函数可能需要执行一些耗时的操作,如读取文件、连接数据库等。使用clone()方法可以避免这些操作,从而提高性能。
在某些场景中,比如组卷场景,可以使用原型模式来创建多份相似的试卷,每份试卷只需要稍作修改即可。比如,如下是一个简单的答辩试题随机卷示例,其题目都来自一样的题库。
下面我们给出一个简单的示例,使用原型来尝试去完成随机出卷。
题目类
简化题目类,只留下一个题干属性title。
试卷类
试卷类,包含一个试卷名字name,以及一个简单的试卷列表,因为要用原型模式,所以先让其实现Cloneable接口,如:
试卷数据准备工具类
编写Client类,测试一下:
Paper paper = PreparePaperDataUtil.prepareTestData();
//克隆试卷对象
Paper clonePaper = paper.clone();
运行一下之后,我们发现克隆出来的对象,其中试题列表的对象是同一个。这是因为继承自是java.lang.Cloneable#clone()方法采用的是浅拷贝。
如果要使克隆出来的对象和原始对象是独立的,我们需要采用深拷贝实现。
同时,修改Paper的clone()方法。
再测试一下,2者的对象都是独立的,修改副本将不会影响原对象。
比对一下new和clone的速度
创建100个对象
创建10000个对象
创建1000000个对象
我们看到,在创建10000个对象的时候,new比clone稍快。所以不是所有情况下clone()方法的速度一定比new快。
我们在Paper的clone方法中,修改点内容随机从中产生不同的试题。
为了方便,同时增加一个试卷内容打印的方法
模拟随机产生5套试卷
这样,一个简单的使用原型设计模式实现的试卷随机组卷示例就完成了。
深拷贝除了对象都实现Clone方法处理外,还有通过序列化反序列化的方法实现。
序列化反序列化实现深拷贝
Clone工具类( 需要实现序列化接口,否则报错 )
其它工具
该方法会执行深拷贝。但所拷贝的对象及其依赖的对象必须实现Serializable接口
与Apache Commons Lang不同,GSON在转换时不需要对象实现Serializable接口。因此我们可以将对象先序列化为JSON字符串,随后再将JSON字符串反序列化为对象。这样实现对象的深拷贝。
有兴趣的读者可以自行尝试一下。
一般情况下
一般情况下,我们可以将一些具体的原型对象放入到缓存,然后使用的时候直接拿出来修改某些值即可。如,本示例的课程答辩试题。
原型模式的优缺点:
优点:
(1):当创建对象的实例较为复杂的时候,使用原型模式可以简化对象的创建过程,通过复制一个已有的实例可以提高实例的创建效率。
(2):扩展性好,由于原型模式提供了抽象原型类,在客户端针对抽象原型类进行编程,而将具体原型类写到配置文件中,增减或减少产品对原有系统都没有影响。
(3):原型模式提供了简化的创建结构,工厂方法模式常常需要有一个与产品类等级结构相同的工厂等级结构,而原型模式不需要这样,圆形模式中产品的复制是通过封装在类中的克隆方法实现的,无需专门的工厂类来创建产品。
(4):可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份并将其状态保存起来,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。
缺点:
(1):需要为每一个类配置一个克隆方法,而且该克隆方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违反了开闭原则。
(2):在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重签到引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。
原型模式的适用环境:
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。