文章目录

  • 前言
  • 正文
    • 一、定义
    • 二、模式结构及分析
      • (一) 模式结构
      • (二) 模式分析
    • 三、情景假设
    • 四、情景分析
      • (一) 浅克隆
      • (二) 深克隆
    • 五、模式优点、缺点
      • (一)模式优点
      • (二)模式缺点
    • 五、使用情景
    • 六、延申及拓展
  • 总结

前言

文章内容主要参考了刘伟主编的《设计模式(第2版)》,同时也结合了自己的一些思考和理解,希望能帮到大家。


本篇文章讲解的是原型模式。

正文

一、定义

原型模式(Prototype Pattern):原型模式是一种对象创建型模式,用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。
原型模式允许通过一个原型对象创建一个或多个同类型的其他对象,而无须知道任何创建的细节;有些对象的创建过程较为复杂,而且需要频繁创建,这时候就可以利用原型模式根据原型进行创建。

二、模式结构及分析

因为模式比较简单,所以先讲解模式,然后再根据案例进一步细化拓展

(一) 模式结构

主要包含的角色

  • Prototype:抽象原型类
  • ConcretePrototype:具体原型类
  • Client:客户类

解释:
首先原型需要复制,很明显复制的方法应该是原型本身提供。所以可以在定义一个抽象原型类Prototype,然后具体实现类各自实现各自的内容,当然也包括克隆方法。之后再客户端client处,创建了一个具体原型,然后就可以调用克隆方法生成多一个克隆对象。

(二) 模式分析

  1. 所有的Java类都继承自java.lang.Object,而Object类提供一个clone()方法,可以将一个Java对象复制一份所以,我们在Java中可以直接使用Object提供的clone()方法来实现对象的克隆(浅克隆)。(这个时候Object类就是Prototype抽象类)
  2. 如果我们需要使用Object的clone()方法,那么Java类必须实现一个标识接口Cloneable,表示这个Java类支持复制,如果一个类没有实现这个接口但是调用了clone()方法,Java编译器将抛出一个CloneNotSupportedException异常
  3. 浅克隆是有问题的,深克隆是我们需要考虑和掌握的。以下案例会提及。
    • 浅克隆(Shallow Clone):当原型对象被复制时,只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制(可以理解为稍微复杂的对象,但是这个不完全对噢~)
    • 深克隆(Deep Clone):除了对象本身被复制外,对象所包含的所有成员变量也将被复制

三、情景假设

由于邮件对象包含的内容较多(如发送者、接收者、标题、内容、日期、附件等),某系统中现需要提供一个邮件复制功能,对于已经创建好的邮件对象,可以通过复制的方式创建一个新的邮件对象,如果需要改变某部分内容,无须修改原始的邮件对象,只需要修改复制后得到的邮件对象即可。使用原型模式设计该系统。
改案例是有两种情况讨论:复制邮件的同时不复制附件(浅克隆)和复制邮件的同时复制附件(深克隆)

四、情景分析

(一) 浅克隆

浅克隆类图

难度不大,Object就是Prototype抽象类,所以我们不用编写,甚至不用继承或实现,因为建立一个类默认就是继承Object类,直接编写Email具体类,重写clone方法(在这里,别以为clone有多难搞,其实本质就是调用父类自己的clone方法),其实。注意的是,要想client成功调用clone方法必须implements Clonable标识接口(标识接口意思是这个接口其实点开看源码里面是全空的,它只是起了一个标记的作用,类似有了一个声明,jvm执行clone方法就会知道它是支持的。)

//Email类
public class Email implements Clonable
{private Attachment attachment = null;//附件类,只是一个辅助类,表示是一个附件public Email(){this.attachment = new Attachment();}public Object clone(){Email clone = null;try{clone = (Email)super.clone();} catch (CloneNotSupportedException e){System.out.println("Clone failure");}return clone;}public Attachment getAttachment(){return this.attachment;}public void display(){System.out.println("查看邮件");}}

接下来就是辅助类:

//附件类Attachment
public class Attachment
{public void download(){System.out.println("下载附件");}
}接下来是客户端的代码:```java
public class Client
{public static void main(String args[]){Email email,copyEmail;email = new Email();copyEmail = (Email)email.clone();System.out.println(emial==copyEmail);System.out.println(email.getAttachment()==copyEmail.getAttachment());}
}

在这里如果运行client,将会输出false和true。首先第一个false起码说明了我们确实创建了一个和之前Email不同的克隆Email,但是第二个true就说明了浅克隆的问题,Attachment是自建对象,在email对象中存储的是引用,而复制之后依旧是复制的是引用,而不是创建一个全新的Attachment对象,(至于为什么这个是存储对象的引用而不是对象本身,可以去搜索java对象的引用了解一下。其实可以这么认为,基本数据类型就是直接复制内容的,除此之外就是复制引用的,所以都会返回true)。
接下里就讲解深克隆(复制邮件的同时也会复制里面的所有附件):

(二) 深克隆

深克隆类图(其实只给了小部分)

注意上图:只给了重点几个类关系,重点就是邮件类和附件类都需要实现Serializable标识接口,接下来看实现:

//Email类
public class Email implements Serializable
{private Attachment attachment = null;//附件类,只是一个辅助类,表示是一个附件public Email(){this.attachment = new Attachment();}public Object deepClone() throws IOException,ClassNotFoundException,OptionalDataException{//将对象写入流中ByteArrayOutputStream bao = new ByteArrayOutputStream();//将流写出到字节数组ObjectOutputStream oos = new ObjectOutputStream(bao);//处理流封装,以对象的方式输出oos.writeObject(this);//处理之后,就可以将对象输出到字节数组//将对象从流中读取ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray());//从字节数组中获取流,这里其实就相当于复制了ObjectInputStream ois = new ObjectInputStream(bis);//将获取的流处理封装,封装成对象return (ois.readObject());//读取对象并输出}public Attachment getAttachment(){return this.attachment;}public void display(){System.out.println("查看邮件");}}

在这里,其实我们是利用序列化的方式,然后将对象写成流,复制,然后转成对象,这样就不是单纯的引用了。

接下来就是辅助类:

//附件类Attachment
public class Attachment implements Serializable
{public void download(){System.out.println("下载附件");}
}

接下来是客户端的代码:

public class Client
{public static void main(String args[]){Email email,copyEmail;email = new Email();copyEmail = (Email)email.clone();System.out.println(emial==copyEmail);System.out.println(email.getAttachment()==copyEmail.getAttachment());}
}

这里的输出就都是false了,因为Email里面的附件复制时我们也是用流的方式搞定的。特别注意,我们想要通过序列化的方式进行复制,就是将整个对象进行序列化,所以Email自己要实现Serializable表示接口(没错,还是标识的作用,并不需要实现具体方法),而我们序列化的过程中,attachment必然也要序列化所以,Attachment也要实现序列化接口。

五、模式优点、缺点

(一)模式优点

  • 简化对象的创建过程,通过复制一个已有实例可以提高新实例的创建效率
  • 扩展性较好
  • 简化创建结构,原型模式中产品的复制是通过封装在原型类中的克隆方法实现的,无须专门的工厂类来创建产品
  • 可以使用深克隆的方式保存对象的状态,以便在需要的时候使用,可辅助实现撤销操作

(二)模式缺点

  • 需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的内部,当对已有的类进行改造时,需要修改源代码,违背了开闭原则
  • 在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重的嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来可能会比较麻烦(需要克隆的对象及其内部所有对象都要保证实现了Serializable接口!!)

五、使用情景

  • 创建新对象成本较大,新对象可以通过复制已有对象来获得,如果是相似对象,则可以对其成员变量稍作修改
  • 系统要保存对象的状态,而对象的状态变化很小
  • 需要避免使用分层次的工厂类来创建分层次的对象

六、延申及拓展

  • 序列化及深克隆过程的理解可能需要知道java IO的知识,大家也可以搜索搜索,深克隆注释写在代码了,看看大家能不能读懂了

总结

本篇文章主要介绍设计模式的原型模式,同时附加了自己的一些小的思考,希望大家也能指出不足。

设计模式(五)—— 原型模式(定义、案例分析、特点、缺点)相关推荐

  1. 设计模式五: 原型模式(Prototype)

    简介 原型模式是属于创建型模式的一种,是通过拷贝原型对象来创建新的对象. 万能的Java超类Object提供了clone()方法来实现对象的拷贝. 可以在以下场景中使用原型模式: 构造函数创建对象成本 ...

  2. C#设计模式(6)——原型模式(Prototype Pattern)

    一.引言 在软件系统中,当创建一个类的实例的过程很昂贵或很复杂,并且我们需要创建多个这样类的实例时,如果我们用new操作符去创建这样的类实例,这未免会增加创建类的复杂度和耗费更多的内存空间,因为这样在 ...

  3. 设计模式回顾——原型模式(C++)

    文章目录 1 前言 2 什么是原型模式 2.1 原型模式组成 2.2 原型模式UML图 2.3 原型模式作用 3 原型模式优缺点 4 什么地方使用原型模式 5 原型模式实现 6 原型模式与构造函数 1 ...

  4. 设计模式之 原型模式

    原型模式应用场景举例:  GG和MM经常在QQ上聊天,但是GG打字的速度慢如蜗牛爬行,每次MM在瞬间完成恢复或者问候是,GG都会很紧张的去尽力快速打字,尽管如此,还是让MM有些不高心,MM说回复信息这 ...

  5. 【设计模式】模板模式——jdbc案例

    系列文章目录 [设计模式]策略模式--支付案例 [设计模式]适配器模式--登录案例 [设计模式]委派模式--登录案例 文章目录 系列文章目录 前言 一.lol案例 二.jdbc案例 总结 前言 假如开 ...

  6. 「设计模式(五) - 代理模式」

    「设计模式(五) - 代理模式」 一.处处可见的"代理" "代理"在平常生活司空见惯,点外卖,租房子找中介,买飞机票等等.基本上用手机就能完成,也就是不直接接触 ...

  7. 【设计模式】 原型模式

    前言: 这篇博客大家可能会看着比较眼熟,但是如果大家在看,就一定要认真看看内容,别跟上一篇混淆* .* 最近,很多人相继开始找工作或者跳槽去找工作,反正就是各种找工作,在当今这个年代,高薪职业不象以前 ...

  8. 【GOF23设计模式】原型模式

    [GOF23设计模式]原型模式 来源:http://www.bjsxt.com/  一.[GOF23设计模式]_原型模式.prototype.浅复制.深复制.Cloneable接口  浅复制 1 pa ...

  9. 设计模式之--原型模式

    1.原型模式定义 原型模式非常简单,定义如下: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象 2.通用类图 原型模式的核心是实现Cloneable接口,此接口为JDK提供的一个标识接 ...

  10. 乐在其中设计模式(C#) - 原型模式(Prototype Pattern)

    [索引页] [源码下载] 乐在其中设计模式(C#) - 原型模式(Prototype Pattern) 作者:webabcd 介绍 用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象. ...

最新文章

  1. 《人件集》阅读笔记第一篇
  2. matlab simulink 四分之一1/4车辆垂向振动模型 轮毂电机
  3. 阿德:工作与发财之间的秘密
  4. 互联网1分钟 |1228
  5. nginx ------反向代理和负载均衡
  6. css 深度选择器 ,CSS的coped私有作用域和深度选择器
  7. 基础拾遗------webservice详解
  8. 前端学习(1501):一次帮别人解决问题的案例
  9. 申请Let's Encrypt永久免费SSL证书
  10. linux ulimit调优
  11. 【Kafka】kafka 再均衡监听器 ConsumerRebalanceListener
  12. 使用Gpg4Win+Outlook Express实现发送和接收加密邮件
  13. [Git] warning: Clone succeeded, but checkout failed.
  14. anndroid 之 Intent(意图)使用示例
  15. C语言-学习笔记完整版
  16. 移动硬盘格式化了的数据找到法子
  17. dk编程真好玩 python_皮皮学编程(1):从Scratch到Python
  18. verilog语言使用注意事项
  19. 进行图像增广的15+种功能总结和Python代码实现
  20. 在爱情里不会委曲求全,活的非常自我,态度十分坚决的三个生肖

热门文章

  1. 可以搭赠鸿蒙系统的手表,4.3英寸屏幕有点小!超大屏智能手机盘点
  2. 2014年度通信行业各大设备商形势分析
  3. 下载chrome离线安装程序的方法
  4. PHP如何实现多服务器session共享
  5. 用JAVA实现简单的扑克牌洗牌发牌并排序
  6. android项目之RRS阅读器
  7. Transmit 5.5.1 for Mac 中文共享版 – 优秀的FTP文件上传下载客户端
  8. 3Dmax阵列工具有哪些使用技巧
  9. 酷我音乐(在线试听)下载方法
  10. 浅析dva (史上最全的dva用法及分析)