设计模式(四)原型模式Prototype(创建型)

1.   概述

我们都知道,创建型模式一般是用来创建一个新的对象,然后我们使用这个对象完成一些对象的操作,我们通过原型模式可以快速的创建一个对象而不需要提供专门的new()操作就可以快速完成对象的创建,这无疑是一种非常有效的方式,快速的创建一个新的对象。

例子1:孙悟空拔下一嘬猴毛,轻轻一吹就会变出好多的孙悟空来。

例子2:寄个快递
下面是一个邮寄快递的场景:
“给我寄个快递。”顾客说。
“寄往什么地方?寄给……?”你问。
“和上次差不多一样,只是邮寄给另外一个地址,这里是邮寄地址……”顾客一边说一边把写有邮寄地址的纸条给你。
“好!”你愉快地答应,因为你保存了用户的以前邮寄信息,只要复制这些数据,然后通过简单的修改就可以快速地创建新的快递数据了。

2. 问题

当对象的构造函数非常复杂,在生成新对象的时候非常耗时间、耗资源的情况?我们是怎么来创建呢?

3. 解决方案

       通过复制(克隆、拷贝)一个指定类型的对象来创建更多同类型的对象。这个指定的对象可被称为“原型”对象,也就是通过复制原型对象来得到更多同类型的对象。即原型设计模式。在php的很多模板库,都用到clone。如smarty等。

4. 适用性

原型模式的主要思想是基于现有的对象克隆一个新的对象出来,一般是有对象的内部提供克隆的方法,通过该方法返回一个对象的副本,这种创建对象的方式,相比我们之前说的几类创建型模式还是有区别的,之前的讲述的工厂模式与抽象工厂都是通过工厂封装具体的new操作的过程,返回一个新的对象,有的时候我们通过这样的创建工厂创建对象不值得,特别是以下的几个场景的时候,可能使用原型模式更简单也效率更高。

• 1)当一个系统应该独立于它的产品创建、构成和表示时,要使用 Prototype模式

• 2)当要实例化的类是在运行时刻指定时,例如,通过动态装载;

• 3)为了避免创建一个与产品类层次平行的工厂类层次时

• 4)当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。(也就是当我们在处理一些对象比较简单,并且对象之间的区别很小,可能只是很固定的几个属性不同的时候,可能我们使用原型模式更合适)。

5. 结构

     原型模式结构如下页上图所示:
       

6. 组成

 

客户(Client)角色:使用原型对象的客户程序
抽象原型(Prototype)角色:规定了具体原型对象必须实现的接口(如果要提供深拷贝,则必须具有实现clone的规定)

具体原型(ConcretePrototype):从抽象原型派生而来,是客户程序使用的对象,即被复制的对象。此角色需要实现抽象原型角色所要求的接口。

7. 效果

Prototype模式有许多和Abstract Factory模式 和 Builder模式一样的效果:它对客户隐藏了具体的产品类,因此减少了客户知道的名字的数目。此外,这些模式使客户无需改变即可使用与特定应用相关的类。
下面列出Prototype模式的另外一些优点。
1 ) 运行时刻增加和删除产品: Prototype允许只通过客户注册原型实例就可以将一个新的具体产品类并入系统。它比其他创建型模式更为灵活,因为客户可以在运行时刻建立和删除原型。
2 ) 改变值以指定新对象: 高度动态的系统允许你通过对象复合定义新的行为—例如,通过为一个对象变量指定值—并且不定义新的类。你通过实例化已有类并且将这些实例注册为客户对象的原型,就可以有效定义新类别的对象。客户可以将职责代理给原型,从而表现出新的行为。这种设计使得用户无需编程即可定义新“类” 。实际上,克隆一个原型类似于实例化一个类。Prototype模式可以极大的减少系统所需要的类的数目。
3) 改变结构以指定新对象:许多应用由部件和子部件来创建对象。
4) 减少子类的构造 Factory Method 经常产生一个与产品类层次平行的 Creator类层次。Prototype模式使得你克隆一个原型而不是请求一个工厂方法去产生一个新的对象。因此你根本不需要Creator类层次。这一优点主要适用于像 C + +这样不将类作为一级类对象的语言。像Smalltalk和Objective C这样的语言从中获益较少,因为你总是可以用一个类对象作为生成者。在这些语言中,类对象已经起到原型一样的作用了。
5) 用类动态配置应用 一些运行时刻环境允许你动态将类装载到应用中。在像 C + +这样的语言中,Prototype模式是利用这种功能的关键。一个希望创建动态载入类的实例的应用不能静态引用类的构造器。而应该由运行环境在载入时自动创建每个类的实例,并用原型管理器来注册这个实例(参见实现一节) 。这样应用就可以向原型管理器请求新装载的类的实例,这些类原本并没有和程序相连接。 E T + +应用框架[ W G M 8 8 ]有一个运行系统就是使用这一方案的。

Prototype的主要缺陷是每一个Prototype的子类都必须实现clone操作,这可能很困难。
例如,当所考虑的类已经存在时就难以新增 clone操作。当内部包括一些不支持拷贝或有循环引用的对象时,实现克隆可能也会很困难的。

8. 实现
  1. <?php
  2. /**
  3. * 原型模式
  4. */
  5. /**
  6. * 抽象原型角色
  7. */
  8. interface Prototype {
  9. public function copy();
  10. }
  11. /**
  12. * 具体原型角色
  13. */
  14. class ConcretePrototype implements Prototype{
  15. private  $_name;
  16. public function __construct($name) {
  17. $this->_name = $name;
  18. }
  19. public function setName($name) {
  20. $this->_name = $name;
  21. }
  22. public function getName() {
  23. return $this->_name;
  24. }
  25. public function copy() {
  26. /** 深拷贝 */
  27. return  clone  $this;
  28. /** 浅拷贝 */
  29. //return  $this;
  30. }
  31. }
  32. class Client {
  33. /**
  34. * Main program.
  35. */
  36. public static function main() {
  37. $object1 = new ConcretePrototype(11);
  38. $object_copy = $object1->copy();
  39. var_dump($object1->getName());
  40. echo '<br />';
  41. var_dump($object_copy->getName());
  42. echo '<br />';
  43. $object1->setName(22);
  44. var_dump($object1->getName());
  45. echo '<br />';
  46. var_dump($object_copy->getName());
  47. echo '<br />';
  48. }
  49. }
  50. Client::main();
  51. ?>
9. 浅拷贝和深拷贝
原型模式的原理图:
浅拷贝
被拷贝对象的所有变量都含有与原对象相同的值,而且对其他对象的引用仍然是指向原来的对象。即浅拷贝只负责当前对象实例,对引用的对象不做拷贝。
浅复制后的对象和对象副本的情况:

深拷贝
被拷贝对象的所有的变量都含有与原来对象相同的值,除了那些引用其他对象的变量。那些引用其他对象的变量将指向一个被拷贝的新对象,而不再是原有那些被引用对象。即 深拷贝把要拷贝的对象所引用的对象也都拷贝了一次,而这种对被引用到的对象拷贝叫做间接拷贝。
深复制的对象和对象副本的情况:
深拷贝要深入到多少层,是一个不确定的问题。
在决定以深拷贝的方式拷贝一个对象的时候,必须决定对间接拷贝的对象是采取浅拷贝还是深拷贝还是继续采用深拷贝。
因此,在采取深拷贝时,需要决定多深才算深。此外,在深拷贝的过程中,很可能会出现循环引用的问题。
 

10. 带Prototype Manager的原型模式

     原型模式的第二种形式是带原型管理器的原型模式,其UML图如下:

     

       原型管理器(Prototype Manager)角色:创建具体原型类的对象,并记录每一个被创建的对象。

下面这个例子演示了在原型管理器中存储用户预先定义的颜色原型,客户通过原型管理器克隆颜色对象。

  1. <?php
  2. /**
  3. * abstract Prototype
  4. *
  5. */
  6. abstract class ColorPrototype
  7. {
  8. //Methods
  9. abstract function  copy();
  10. }
  11. /**
  12. * Concrete Prototype
  13. *
  14. */
  15. class Color extends ColorPrototype{
  16. //Fields
  17. private  $red;
  18. private  $green;
  19. private  $blue;
  20. //Constructors
  21. function __construct( $red, $green, $red) {
  22. $this->red = $red;
  23. $this->green = $green;
  24. $this->blue = $red;
  25. }
  26. /**
  27. * set red
  28. *
  29. * @param unknown_type $red
  30. */
  31. public  function setRed($red) {
  32. $this->red = $red;
  33. }
  34. /**
  35. * get red
  36. *
  37. */
  38. public  function getRed(){
  39. return  $this->red;
  40. }
  41. /**
  42. *set Green
  43. *
  44. * @param  $green
  45. */
  46. public  function setGreen($green) {
  47. $this->green = $green;
  48. }
  49. /**
  50. * get Green
  51. *
  52. * @return unknown
  53. */
  54. public  function getGreen() {
  55. return  $this->green ;
  56. }
  57. /**
  58. *set Blue
  59. *
  60. * @param  $Blue
  61. */
  62. public  function setBlue($Blue) {
  63. $this->blue = $Blue;
  64. }
  65. /**
  66. * get Blue
  67. *
  68. * @return unknown
  69. */
  70. public  function getBlue() {
  71. return  $this->blue ;
  72. }
  73. /**
  74. * Enter description here...
  75. *
  76. * @return unknown
  77. */
  78. function copy(){
  79. return clone $this;
  80. }
  81. function display() {
  82. echo $this->red , ',', $this->green, ',', $this->blue ,'<br>';
  83. }
  84. }
  85. /**
  86. * Enter description here...
  87. *
  88. */
  89. class ColorManager
  90. {
  91. // Fields
  92. static  $colors = array();
  93. // Indexers
  94. public static function add($name, $value){
  95. self::$colors[$name] = $value;
  96. }
  97. public static function getCopy($name) {
  98. return   self::$colors[$name]->copy();
  99. }
  100. }
  101. /**
  102. *Client
  103. *
  104. */
  105. class Client
  106. {
  107. public static function  Main()
  108. {
  109. //原型:白色
  110. ColorManager::add("white", new Color( 255, 0, 0 ));
  111. //红色可以由原型白色对象得到,只是重新修改白色: r
  112. $red = ColorManager::getCopy('white');
  113. $red->setRed(255);
  114. $red->display();
  115. //绿色可以由原型白色对象得到,只是重新修改白色: g
  116. $green = ColorManager::getCopy('white');
  117. $green->setGreen(255);
  118. $green->display();
  119. //绿色可以由原型白色对象得到,只是重新修改白色: b
  120. $Blue = ColorManager::getCopy('white');
  121. $Blue->setBlue(255);
  122. $Blue->display();
  123. }
  124. }
  125. ini_set('display_errors', 'On');
  126. error_reporting(E_ALL & ~ E_DEPRECATED);
  127. Client::Main();
  128. ?>

设计模式(四)原型模式Prototype(创建型)的更多相关文章

  1. 原型模式 prototype 创建型 设计模式(七)

    原型模式  prototype 意图 用原型实例指定需要创建的对象的类型,然后使用复制这个原型对象的方法创建出更多同类型的对象   显然,原型模式就是给出一个对象,然后克隆一个或者更多个对象 小时候看 ...

  2. Java设计模式05:常用设计模式之原型模式(创建型模式)

    1. Java之原型模式(Prototype Pattern)     原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象. ...

  3. 设计模式05: Prototype 原型模式(创建型模式)

    Prototype 原型模式(创建型模式) 依赖关系的倒置抽象不应该依赖于实现细节,细节应该依赖于抽象.对所有的设计模式都是这样的. -抽象A直接依赖于实现细节b -抽象A依赖于抽象B,实现细节b依赖 ...

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

    原文:乐在其中设计模式(C#) - 原型模式(Prototype Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 原型模式(Prototype Pattern) 作者:weba ...

  5. 二十四种设计模式:原型模式(Prototype Pattern)

    原型模式(Prototype Pattern) 介绍用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象.示例有一个Message实体类,现在要克隆它. MessageModel usin ...

  6. 创建型设计模式之原型模式(Prototype)

    结构   意图 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 适用性 当要实例化的类是在运行时刻指定时,例如,通过动态装载:或者 为了避免创建一个与产品类层次平行的工厂类层次时:或 ...

  7. 设计模式 笔记 原型模式 prototype

    //---------------------------15/04/07---------------------------- //prototype 原型模式--对象创建型模式 /* 1:意图: ...

  8. php设计模式四 ---- 原型模式

    1.简介 用于创建重复的对象,同时又能保证性能.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式 意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 主要解决:在运 ...

  9. 【UE4 设计模式】原型模式 Prototype Pattern

    概述 描述 使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.如孙悟空猴毛分身.鸣人影之分身.剑光分化.无限剑制 原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象, ...

  10. [设计模式] 4 原型模式 prototype

    设计模式:可复用面向对象软件的基础>(DP)本文介绍原型模式和模板方法模式的实现.首先介绍原型模式,然后引出模板方法模式. DP书上的定义为:用原型实例指定创建对象的种类,并且通过拷贝这些原型创 ...

随机推荐

  1. Qt的“undefined reference to `vtable for”错误解决(手动解决,加深理解)

    使用QT编程时,当用户自定义了一个类,只要类中使用了信号或槽. Code::Blocks编译就会报错(undefined reference to `vtable for). Google上有很多这个 ...

  2. JavaEE Tutorials (9) - 运行持久化示例

    9.1order应用118 9.1.1order应用中的实体关系119 9.1.2order应用中的主键121 9.1.3实体映射到多个数据库表125 9.1.4order应用中的层叠操作125 9. ...

  3. robomongo

    Robomongo 是一个可视化的mongodb数据库工具,提供对mongodb的操作,javascript执行及语法高亮提示. 安装教程

  4. 如何自定义iOS中的控件

    本文译自 How to build a custom control in iOS .大家要是有什么问题,可以直接在 twitter 上联系原作者,当然也可以在最后的评论中回复我. 在开发过程中,有时 ...

  5. Extending your SharePoint 2007 site with Microsoft ASP.NET AJAX 3.5

    After ASP.NET 3.5 has been installed you need to modify the web.config file of your MOSS web site wi ...

  6. C3P0连接池参数解释

    <!--acquireIncrement:链接用完了自动增量3个. --> <property name="acquireIncrement">3</ ...

  7. JAVA虚拟机内存模型

    一.对于Java程序员来说,在虚拟机的自动内存管理机制下,我们不需要为每一个new操作去写匹配的delete/free操作 但是当我们对于内存的管理了解有能够帮助我们理解Java虚拟机的垃圾回收机制. ...

  8. 英文:known good board ( KGB) / 中文:测试用标准板,黄金板

    作为标准部件提供的.完全符合设计电气性能的在制板,可以作为与其它印制板比较的标准.

  9. hibernate 延长加载范围 4.2

    1. 关闭延迟加载功能 lazy="false"2.修改抓取策略 fetch="join"直接查询关联数据,一个联接查询搞定3.使用Hibernate对象的in ...

  10. SiteMesh

    1.导入对SiteMesh.jar的依赖 <dependency>      <groupId>org.sitemesh</groupId>      <ar ...