热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

设计模式~原始模型模式

原始模型(Prototype)模式属于对象的创建模式。

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

Java对象的复制

Java的所有类都是从 java.lang.Object 类继承而来的,而 Object 类提供下面的方法对对象进行复制:

protected Object clone()

子类也可以把这个方法置换掉,提供满足自己需要的复制方法。

Java语言提供的Cloneable接口只有一个作用,就是在运行时期通知Java虚拟机可以安全的在这个类上使用 clone() 方法。

由于Object 类本身并不实现 Cloneable 接口,因此如果所考虑的类没有实现Cloneable接口时,调用 clone() 方法会抛出 CloneNotSupportedException 异常。

克隆满足的条件

一般而言, clone() 方法满足以下描述:

  1. 对任何的对象 x , 都有: x.clone() != x 。 也就是说,克隆对象与原对象不是同一个对象。
  2. 对任何的对象 x , 都有: x.clone().getClass == x.getClass(), 也就是说克隆对象与原对象的类型一样。
  3. 如果对象的 x 的 equals()方法定义恰当的话,x.clone().equals(x) 应当是成立的。

简单形式的原始模型模式

设计模式~原始模型模式

 

 涉及三个角色:

  • 客户角色(Client):客户类提出创建对象的请求。
  • 抽象原型角色(Prototype): 这是一个抽象角色,通常由一个Java接口或Java抽象类实现。此角色给出所有具体原型类所需的接口。
  • 具体原型角色(Concrete Prototype): 被复制的对象。此角色需要实现抽象的原型角色所要求的接口。

示意性源码

设计模式~原始模型模式

 

 设计模式~原始模型模式

 

设计模式~原始模型模式

 

登记形式的原始模型模式

设计模式~原始模型模式

 角色如下:

  • 客户端角色(Client): 客户端类向管理员提出创建对象的请求。
  • 抽象原型角色(Prototype):此角色给出所有具体原型类所需的接口。
  • 具体原型角色(Concrete Prototype): 被复制的对象。需要实现抽象的原型角色所要求的接口。
  • 原型管理器角色(Prototype Manager): 创建具体原型类的对象,并记录每一个被创建的对象

设计模式~原始模型模式

设计模式~原始模型模式

 

 设计模式~原始模型模式

 

 设计模式~原始模型模式

 

 设计模式~原始模型模式

 

 两种形式的比较

如果需要创建的原型对象数目较少而且比较固定,可以采用第一种形式,即简单形式的原始模型模式。这种模式中,原型对象的引用可以由客户端自己保存。

如果要创建的原型对象数目不固定的话,可以采用第二种形式,即登记形式的原始模型模式。这种模式中,由管理员保存原型对象的引用。

 模式的实现:深复制和浅复制

浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。

深复制把要复制的对象所引用的对象都复制了一遍,而这种对被引用到的对象的复制叫做间接复制。

深复制要深入到多少层,是一个不易确定的问题。在决定以深复制的方式复制一个对象的时候,必须决定对间接复制的对象是采取浅复制还是继续采取深复制。因此,在采取深复制时,需要决定多深才算深。此外,在深复制的过程中,很可能会出现循环引用的问题,必须小心处理。

利用串行化来做深复制

把对象写到流里的过程是串行化(Serilization)过程;而把对象从流中读出来过程叫做并行化过程。

应当指出的是,写到流里的是对象的拷贝,而原对象仍然存在于JVM里面。

在java语言里深复制一个对象,常常可以先使对象实现 Serialization 接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里,再从流里读回来,便可以重建对象。

深复制的源代码

设计模式~原始模型模式

 

 这样做的前提就是对象以及对象内部所有引用到的对象都是可串行化的,否则,就需要仔细考察那些不可串行化的对象是否可以设成 transient, 从而将之排除在复制过程之外。

在什么情况下使用原始模型模式

假设一个系统的产品类是动态加载的,而且产品类具有一定的等级结构。这个时候如果采取工厂模式的话,工厂类就不得不具有一个相应的等级结构。而产品类的等级结构一旦变化,工厂类的的等级结构就不得不有一个相应的变化。这对于产品结构可能会有经常性变化的系统来说,采用工厂模式就有不方便之处。

  这时如果采用原始模型模式,给每一个产品类配备一个克隆方法(大多数时候只需要给产品类等级结构的根类配备一个克隆方法),便可以避免使用工厂模式所带来的具有固化等级结构的工厂类。

  这样,一个使用了原始模型模式的系统与它的产品对象是怎么创建出来的,以及这些产品对象之间的结构是怎样的,以及这些结构会不会发生变化时没有关系的。

原始模型模式的优点和缺点

抽象工厂模式有许多与原始模型模式和建造模式相同的效果,包括客户端不知道具体产品类,而只知道抽象产品类,客户端不需要知道这么多的具体产品名称。如果有新的产品类加入,客户端不需要进行改造就可直接使用。

原始模型模式有其特有的优点

  1. 原始模型模式允许动态的增加或减少产品类。由于创建产品类实例的方法是产品类内部具有的,因此,增加新产品对整个结构没有影响。
  2. 原始原型模式提供简化的创建结构。
  3. 具有给一个应用软件动态加载新功能的结构。
  4. 产品类不需要非得有任何事先确定的等级结构,因为原始模型模式适用于任何的等级结构。

原始模型模式的最主要的缺点是每一个类都必须配备一个克隆方法

配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类来说不是很难。

而对于已经有的类不一定很容易,特别是当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。

 


推荐阅读
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • CEPH LIO iSCSI Gateway及其使用参考文档
    本文介绍了CEPH LIO iSCSI Gateway以及使用该网关的参考文档,包括Ceph Block Device、CEPH ISCSI GATEWAY、USING AN ISCSI GATEWAY等。同时提供了多个参考链接,详细介绍了CEPH LIO iSCSI Gateway的配置和使用方法。 ... [详细]
  • 移动端常用单位——rem的使用方法和注意事项
    本文介绍了移动端常用的单位rem的使用方法和注意事项,包括px、%、em、vw、vh等其他常用单位的比较。同时还介绍了如何通过JS获取视口宽度并动态调整rem的值,以适应不同设备的屏幕大小。此外,还提到了rem目前在移动端的主流地位。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • CentOS 6.5安装VMware Tools及共享文件夹显示问题解决方法
    本文介绍了在CentOS 6.5上安装VMware Tools及解决共享文件夹显示问题的方法。包括清空CD/DVD使用的ISO镜像文件、创建挂载目录、改变光驱设备的读写权限等步骤。最后给出了拷贝解压VMware Tools的操作。 ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
author-avatar
我是个密_916
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有