当前位置:首页 > 设计模式 > 正文内容

php中原型模式

phpmianshi9年前 (2012-04-11)设计模式222

概念


原型模式(Prototype Pattern):与工厂模式类似,都是用来创建对象的。利用克隆来生成一个大对象,减少创建时的初始化等操作占用开销


场景

多用于创建大对象,或初始化繁琐的对象。如游戏中的背景,地图。web中的画布等等

1,有些时候,我们需要创建多个类似的大对象。如果直接通过new对象,开销很大,而且new完还得进行重复的初始化工作。可能把初始化工作封装起来的,但是对于系统来说,你封不封装,初始化工作还是要执行。,

2,原型模式则不同,原型模式是先创建好一个原型对象,然后通过clone这个原型对象来创建新的对象,这样就免去了重复的初始化工作,系统仅需内存拷贝即可。


结构图

图片描述

示例

如果说,我们现在正开发一个游戏,有不同的地图,地图大小都是一样的,并且都有海洋,但是不同的地图温度不一样。

<?php

//抽象原型类
abstract class Prototype
{
    abstract function __clone();
}

//具体原型类
class Map extends Prototype
{
    public $width;
    public $height;
    public $sea;


    public function setAttribute(array $attributes)
    {
        foreach ($attributes as $key => $val) {
            $this->$key = $val;
        }
    }

    public function __clone()
    {
    }
}

//海洋类.这里就不具体实现了。
class Sea
{
}

//使用原型模式创建对象方法如下
//先创建一个原型对象
$map_prototype = new Map;
$attributes = array('width' => 40, 'height' => 60, 'sea' => (new Sea));
$map_prototype->setAttribute($attributes);
//现在已经创建好原型对象了。如果我们要创建一个新的map对象只需要克隆一下
$new_map = clone $map_prototype;

var_dump($map_prototype);
var_dump($new_map);

通过上面的代码,我们可以发现利用原型模式,只需要实例化并初始化一个地图原型对象。以后生产一个地图对象,都可以直接通过clone原型对象产生。省去了重新初始化的过程。

但是上面的代码还是存在一些问题。那就是它只是一个浅拷贝,什么意思呢?map原型对象有一个属性sea存放了一个sea对象,在调用setAttribute的时候,对象的赋值方式默认是引用。而当我们克隆map对象时,直接克隆了map的sea属性,这就使得克隆出来的对象与原型对象的sea属性对指向了,同一个sea对象的内存空间。如果这个时候,我们改变了克隆对象的sea属性,那么原型对象的sea属性也跟着改变。

这显然是不合理的,我们想要的结果应该是深拷贝,也就是改变克隆对象的所有属性,包括用来存放sea这种其他对象的属性时,也不影响原型对象。
当然,讲到这里你可以当我在胡说。但我还是建议你打印下原型对象和克隆对象,看一下他们的sea属性吧,然后去好好了解一下什么叫深拷贝和浅拷贝。


深拷贝的实现

深拷贝的实现,其实也简单,我们只要实现Map类的克隆方法就行了。这就是我们为什么要定义一个抽象原型类的原因。我们利用抽象类,强制所有继承的具体原型类都必须来实现这个克隆方法。改进如下:

<?php

//具体原型类
class Map extends Prototype
{
    public $width;
    public $height;
    public $sea;

    public function setAttribute(array $attributes)
    {
        foreach ($attributes as $key => $val) {
            $this->$key = $val;
        }
    }

    //实现克隆方法,用来实现深拷贝
    public function __clone()
    {
        $this->sea = clone $this->sea;
    }
}





版权声明:本文由PHP面试资料网发布,如需转载请注明出处。
分享给朋友:

相关文章

Laravel神奇的IoC容器

Laravel 的核心就是一个 IoC 容器,根据文档,称其为“服务容器”通过举例来让读者去理解什么是 IoC(控制反转) 和 DI(依赖注入)超人和超能力,依...

php中装饰器模式

概念装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。这种模式创建了一个装饰类,用来包...

php中的模板模式

概念在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。定义一个操作中的算法的骨架,而将一...

php中的流接口模式

概念 流接口模式(Fluent Interface)用来编写易于阅读的代码,就像自然语言一样(如英语),最关键的一步是:操作函数中必须 return $this,即返回本对象,以调用后续的方...

代理模式、桥接模式、中介者模式区别和联系

联系    在现实生活中,如房屋中介、买房人、卖房人,房屋中介是一个中介,因为它担任买房人和卖房人之间的相同;房屋中介也是一个代理,它在卖房人眼前是买房人的代理,在卖房人...

对象池模式和注册树模式的区别和联系

区别对象池主在对象创建开销较大或要控制对象数量的时候使用。最常见的对象池应该是数据库连接池和线程池,例如程序需要数据库连接时从连接池中取一个(连接池里有多个连接),用完了不是关闭连接而是把连接放回连接...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。