前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >漫谈模式之原型模式

漫谈模式之原型模式

作者头像
孟君
发布2023-03-10 09:21:39
2950
发布2023-03-10 09:21:39
举报

在之前的几篇博文已经介绍了只创建一个实例的单例模式( Singleton ),以及一步步创建复杂对象的建造者模式( Builder )。本文继续来介绍创建型模式的另外一个:原型模式,原型模式(Prototype Pattern)是一种创建型设计模式,它允许通过复制现有对象来创建新对象,而不是使用显式的构造函数来创建新对象

接下来,我们主要从如下几个方面来进行讲解。

  • 原型模式的基本介绍
  • 为什么要使用Clone?
  • 使用原型模式来简单实现随机答辩试卷
  • 浅复制和深复制介绍
  • 实现深度复制的方法
  • ... ... 

原型模式的基本介绍

原型模式是一种创建型模式。通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的方法创建出更多同类型的对象。

意图

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

结构

原型模式的基本结构如下:

图片
图片

这里涉及的参与者有如下几种:

  • Prototype(抽象原型)
    • 通常由一个接口或者抽象类实现。此角色给出所有的具体原型所需的接口
  • Concrete Prototype(具体原型)
    • 实现一个克隆自身的操作
  • Client(客户)
    • 提出创建对象的请求,让一个原型克隆自身从而创建一个新的对象。

在Java中,可以使用clone()方法来实现原型模式。

为什么要使用Clone呢?

在Java中,使用clone()方法可以创建一个新的对象副本,对它进行修改不会影响原始对象。在某些情况下,使用clone()方法可以比创建新的对象更快。这是因为clone()方法不需要调用构造函数。在某些情况下,构造函数可能需要执行一些耗时的操作,如读取文件、连接数据库等。使用clone()方法可以避免这些操作,从而提高性能。

在某些场景中,比如组卷场景,可以使用原型模式来创建多份相似的试卷,每份试卷只需要稍作修改即可。比如,如下是一个简单的答辩试题随机卷示例,其题目都来自一样的题库。

图片
图片

试卷原型模式完成

下面我们给出一个简单的示例,使用原型来尝试去完成随机出卷。

题目类

简化题目类,只留下一个题干属性title。

图片
图片

试卷类

试卷类,包含一个试卷名字name,以及一个简单的试卷列表,因为要用原型模式,所以先让其实现Cloneable接口,如:

图片
图片

试卷数据准备工具类

图片
图片

编写Client类,测试一下:

代码语言:javascript
复制
  Paper paper = PreparePaperDataUtil.prepareTestData(); 
  //克隆试卷对象  
  Paper clonePaper = paper.clone();
图片
图片

运行一下之后,我们发现克隆出来的对象,其中试题列表的对象是同一个。这是因为继承自是java.lang.Cloneable#clone()方法采用的是浅拷贝。

图片
图片

如果要使克隆出来的对象和原始对象是独立的,我们需要采用深拷贝实现。

图片
图片

在本示例中,如果要实现深拷贝,我们需要让Question类也实现Cloneable接口。

图片
图片

同时,修改Paper的clone()方法。

图片
图片

再测试一下,2者的对象都是独立的,修改副本将不会影响原对象。

图片
图片

比对一下new和clone的速度

创建100个对象

创建10000个对象

图片
图片

创建1000000个对象

图片
图片

我们看到,在创建10000个对象的时候,new比clone稍快。所以不是所有情况下clone()方法的速度一定比new快。

模拟产生多套试卷

我们在Paper的clone方法中,修改点内容随机从中产生不同的试题。

图片
图片

为了方便,同时增加一个试卷内容打印的方法

图片
图片

模拟随机产生5套试卷

图片
图片

这样,一个简单的使用原型设计模式实现的试卷随机组卷示例就完成了。

深拷贝的方法

深拷贝除了对象都实现Clone方法处理外,还有通过序列化反序列化的方法实现。

序列化反序列化实现深拷贝

Clone工具类( 需要实现序列化接口,否则报错 )

图片
图片

其它工具

  • Apache Commons Lang有一个SerializationUtils#clone方法

该方法会执行深拷贝。但所拷贝的对象及其依赖的对象必须实现Serializable接口

  • Gson可以用来将对象转换为JSON,反之亦然

与Apache Commons Lang不同,GSON在转换时不需要对象实现Serializable接口。因此我们可以将对象先序列化为JSON字符串,随后再将JSON字符串反序列化为对象。这样实现对象的深拷贝。

有兴趣的读者可以自行尝试一下。

优缺点适用环境

一般情况下

一般情况下,我们可以将一些具体的原型对象放入到缓存,然后使用的时候直接拿出来修改某些值即可。如,本示例的课程答辩试题。

原型模式的优缺点:

优点:

(1):当创建对象的实例较为复杂的时候,使用原型模式可以简化对象的创建过程,通过复制一个已有的实例可以提高实例的创建效率。

(2):扩展性好,由于原型模式提供了抽象原型类,在客户端针对抽象原型类进行编程,而将具体原型类写到配置文件中,增减或减少产品对原有系统都没有影响。

(3):原型模式提供了简化的创建结构,工厂方法模式常常需要有一个与产品类等级结构相同的工厂等级结构,而原型模式不需要这样,圆形模式中产品的复制是通过封装在类中的克隆方法实现的,无需专门的工厂类来创建产品。

(4):可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份并将其状态保存起来,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。

缺点:

(1):需要为每一个类配置一个克隆方法,而且该克隆方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违反了开闭原则。

(2):在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重签到引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。

原型模式的适用环境:

  • 创建新对象成本较大(例如初始化时间长,占用CPU多或占太多网络资源),新对象可以通过复制已有对象来获得,如果相似对象,则可以对其成员变量稍作修改。
  • 系统要保存对象的状态,而对象的状态很小。
  • 需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少的组合状态,通过复制原型对象得到新实例可以比使用构造函数创建一个新实例更加方便。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 原型模式的基本介绍
  • 试卷原型模式完成
  • 在本示例中,如果要实现深拷贝,我们需要让Question类也实现Cloneable接口。
  • 模拟产生多套试卷
  • 深拷贝的方法
  • 优缺点适用环境
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档