设计模式专题(六)——原型模式

设计模式专题(六)

——原型模式

(原创内容,转载请注明来源,谢谢)

一、含义

原型模式(Prototype)是用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式实现从一个对象创建另外一个可以定制的对象,而不需要知道里面的细节。

因此,原型模式实现了克隆对象的功能,主要是把里面的非静态属性都克隆过来,如果是值类型就复制值,如果是引用、指向对象的,则另其指向一个新的对象,且其值和原值相同。这样,当要调用多次类的实例,且每次不一样,就不需要每次都去new,只需要克隆即可。

二、类图

三、实现方式

类的复制有深度复制与浅复制。

1、场景

现假设有两个类,Prototype类用于测试复制,Test类用于给属性赋值。$prototypeA实例化Prototype类,此时需要新增prototypeB实例。

         classPrototype{
         public $propStr;
         public $propArr;
         public $propObj;
         public function__construct($str, $arr, $obj){
                   $this->propStr= $str;
                   $this->propArr= $arr;
                   $this->propObj= $obj;
         }
}
class Test{
         public $testStr;
         public function__construct($str){
                   $this->testStr= $str;
         }
}
$prototypeA = new Prototype(
         'a',
         array('a', array('aa','aaa')),
         new Test('atest')
);

2、直接指向——$prototypeB=$prototypeA

此时,两个变量中的任意一个改动了其属性,另一个也会跟着改动。

3、浅复制——$prototypeB=clone$prototypeA

此时prototypeA中值类型的数据(数字、字符串、数组)可以完全复制过去到prototypeB,且prototypeB改动的情况下不会影响到prototypeA。但是,prototypeA的属性中如果有对象,则prototypeB如果对prototypeA的对象中的属性进行重新赋值,则prototypeA中相应的指向该对象的属性也一样会改动。

即,假设此时$prototypeB->propObj->testStr= 'btest'; 则A的propObj->testStr也是’btest’。

但是,如果不是直接操作属性指向的对象中的属性,则不会影响另一个变量。

如$prototypeB->propObj=newTest(‘btest’);或者等于其他任何的值,则A的propObj->testStr仍是’atest’。

4、深复制(1)——$prototypeB=unserialize(serialize($prototypeA))或json_decode(json_encode($prototypeA))

当将对象序列化或者转成json以后,即将对象完全转成字符串了,此时再还原字符串,则可以将B和A完全分离,即B是一个全新的A,两者无论如何改动自身都不影响到对方。

5、深复制(2)——魔术方法__clone()

当使用clone时,会自动调用类中的函数__clone(),如果没有定义则默认按照浅复制的方式对类进行复制。但是如果有定义的情况下,则可以根据需要进行复制。

例如:

         public function __clone(){
         //获取对象的所有属性值
         $object_vars= get_object_vars($this);
         foreach($object_vars as $attr_name => $attr_value){
                   //如果是对象,则用clone完全复制
                   if(is_object($this->$attr_name)){
                            $this->$attr_name= clone $this->$attr_name;
                   }elseif (is_array($this->$attr_name)){
                            //如果是数组,则逐个检查数组中的元素,如果元素中有对象则还需要clone
                            //这个只能完成一维数组的检查,如果是多维数组,需要用递归的方式检查
                            foreach($this->$attr_name as &$attr_array_value)
                            {
                                     if(is_object($attr_array_value))
                                     {
                                               $attr_array_value= clone $attr_array_value;
                                     }
                                     unset($attr_array_value);
                            }
                   }          
         }
}

但此方式较为复杂,如果仅仅需要实现深度复制,还是用序列化或者json比较方便快捷。

通常__clone()魔术方法是为了控制复制的内容,当部分信息不希望被复制时才建立此方法,对具体的属性进行控制。

——written by linhxx 2017.07.31

相关阅读:

设计模式专题(五)——工厂方法模式

设计模式专题(四)——代理模式

设计模式专题(三)——装饰模式

设计模式专题(二)——策略模式

设计模式专题(一)——面向对象的设计原则

原文发布于微信公众号 - 决胜机器学习(phpthinker)

原文发表时间:2017-07-31

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Phoenix的Android之旅

重构-委托代替继承

继承是面向对象语言的优秀设计理念,但是滥用继承也会导致一些不必要的麻烦。 当我们写代码要继承某个类的是首先要考虑这些东西, · 子类是否需要父类的大部分功能 ·...

772
来自专栏十月梦想

构建函数(class)创建对象,对象属性新增和修改

构建函数创建对象类似函数,内部的属性方法用分号分离,json创建的对象各类属性方法用逗号可开

472
来自专栏偏前端工程师的驿站

Javascript Prototypes之旅(A Plain English Guide to JavaScript Prototypes译文)

  当我第一次学习Javascript的对象模型时,我的反应时困惑。因为这是我第一次接触基于原型的语言,所以我完完全全被原型弄得糊里糊涂(译者语:在看这篇文章前...

1759
来自专栏小二的折腾日记

《effective C++》from line 1 to line 12

包含着最初的以c语言为基础的C,面向对象的C++,C++的泛型编程,以及STL。在我们使用的过程中,可能会穿插,但是我们需要根据不同的情况使用不同的策略。

673
来自专栏C/C++基础

内存池介绍与经典内存池的实现

利用默认的内存管理函数new/delete或malloc/free在堆上分配和释放内存会有一些额外的开销。

691
来自专栏向治洪

java造成内存泄露原因

一、Java内存回收机制  不论哪种语言的内存分配方式,都需要返回所分配内存的真实地址,也就是返回一个指针到内存块的首地址。Java中对象是采用new或者反射的...

17510
来自专栏C/C++基础

C++ new的三种面貌

C++中使用new运算符产生一个存在于Heap(堆)上对象时,实际上调用了operator new()函数和placement new()函数。在使用new创建...

731
来自专栏老九学堂

【超全】C语言初学者必须掌握的关键字!

其实小伙伴在写代码的时候,关键字还是用的比较多的,老九主要就平常中用到的常用关键字进行总结,便于小伙伴们更全面的理解其在代码中的意图。 C语言关键字总结 sta...

3396
来自专栏玄魂工作室

《改善C程序代码的125个建议》-防止整数类型产生回绕与溢出

以下内容摘抄自《改善C程序代码的125个建议》: 建议2:防止整数类型产生回绕与溢出 到C99为止,C语言为我们提供了12个相关的数据类型关键字来表达各种数据...

2787
来自专栏Modeng的专栏

Javascript数组系列一之栈与队列

所谓数组(英语:Array),是有序的元素序列。 若将有限个类型相同的变量的集合命名,那么这个名称为数组名。 组成数组的各个变量称为数组的分量,也称为数组的元素...

1065

扫码关注云+社区