php中的组合模式

刚看完了《深入php面向对象、模式与实践》一书中组合模式这块内容,为了加深理解和记忆,所以着手写了这篇博客。

为方便后续理解,此处先引入两个概念,局部对象和组合对象。

局部对象:无法将其他对象组合到自身内部属性上的对象。即不能组合其他对象的对象。

组合对象:可以将其他对象组合到自身内部属性上的对象。即可以组合其他对象的对象。

注:将对象A的某个属性中存储着对象B对象的引用,则表示A与B有组合关系,其中A将B组合到了自身内部。

首先我们通过给出下面的业务需求,来引入组合模式:

业务部门想要开发一款类似于红色警戒的战斗游戏,初始局部战斗单元有两个:射手(Archer)和激光炮(LaserCannon),组合战斗单元可以有多种(由两个局部单元组合成的组合战斗单元,或者由组合单元和局部战斗单元组合成的组合战斗单元,这里随着子对象的不同,组合对象有多种)。其中组合单元和局部单元都具有战斗单元共有的属性(攻击能力,移动能力和防御能力)。而组合单元中的属性值是其子对象对应属性值的和。因为组合对象的子对象需要根据情况不断变化,那么其对应的属性值也需要不断更新和变化,这里我们需要采用什么样的组合方式考才能方便的更新和获取组合对象的属性值呢,这里就需要用到我们今天讲的组合模式了。

组合模式:

1、定义:将一组对象组合为可像单个对象一样被使用的结构。(即组合对象中获取属性值可如局部对象中一样方便)

2、分类:组合模式分为两种,透明模式和安全模式

2、实现方法:

分析:组合对象如何才可以很方便计算出属性值呢?如果可以很方便获取其子对象中的对应属性,则可以通过求和得出。那么如何方便的得到子对象中的对应属性值呢?这里主要挑战在于如何知道包含哪些子对象呢,当然最简单的方法就是在组合对象中保留子对象的引用,将所有子对象存储在一个数据结构为数组的属性中,这样我们就可以在获取属性值的方法中循环遍历该数组,然后通过求和算出组合对象的属性值。具体代码如下:

abstract class Unit
{
    // 用来获取战斗单元的攻击属性值
    abstract function bomstrength();
}

// 局部战斗单元(射手)
class Archer extends Unit
{
    function bomstrength()
    {
        return 4;
    }
}
//局部战斗单元(激光炮)
class LaserCannonUnit extends Unit
{
    function bomstrength()
    {
        return 44;
    }
}
// 组合战斗单元
class Army extends Unit
{
    private $units = array();//用来存储子对象

    // 用来添加子对象
    function addUnit(Unit $unit)
    {
        array_push($this->units, $unit);
    }

    // 用来计算攻击属性值
    function bomstrength()
    {
        $ret = 0;
        foreach($this->units as $unit)
        {
            $ret += $unit->bomStrength();
        }
    }
}

上面正是满足我们需求的代码,但是更多时候客户端不需要区分对象是Army、Unit还是其他组合对象,就功能上,这些组合模式是相同的,都具有移动、攻击和防御的功能。这些特点让我们很容易想到,让他们共享同一个类型家族(这就是组合模式)。

下面是组合模式下透明和安全两种方式的实现方式:

透明模式:

abstract class Unit
{
    abstract functon addUnit (Unit $unit);
    abstract function removeUnit (Unit $unit);
    abstract function bomStrength();
}

Army class extends Unit
{
    private $units =array();

    public function addUnit(Unit $unit)
    {
        if(in_array($unit, $this->units, true))
        {
            return;
        }
    }

    public function removeUnit($unit)
    {
        $this->units = array_udiff($this->units, array($unit), function($a, $b) { return ($a===$b) ?0:1});
    }

    public function bomStrength()
    {
        $ret = 0;
        foreach($this->units as $unit)
        {
            $ret += $unit->bomStrength();
        }
    }

}

这里Army可以保存任何类型的Unit对象,包括Army本身或者Archer或者LaserCannon这样的局部对象。因为所有Unit对象都保证支持bomStrength方法,所以我们Army::bomStrength只需遍历$units发展,调用每个Unit对象的bomStrength方法,就可以计算出带动军队的攻击强度了。

但是实际上,我们不需要在Archer上添加Unit对象,所以当Archer或者LaserCannon这种局部对象调用addUnit或者removeUnit方法时需要抛出异常,我们可以在抽象类中指定这两个方法抛出异常,只在组合对象中重写这两个函数。这种就是组合模式中的透明模式,特点就是对客户端透明,无论是局部对象还是组合对象,方法是公有的,不过这里有很明显的缺点:当局部对象调用removeUnit或者addUnit方法时虽然方法存在,但是只会给出异常,这是我们在运行中不想遇到的,有没有方法可以实现共用一个父类,同时不会出现不可预期的报错行为的方法呢。当然有,这就量组合模式的另一种模式,安全模式。

安全模式:

abstract class Unit
{    function getComposite()    {       return null;     }
    abstract function bomStrength();
}

class CompositeUnit extends Unit
{
    private $units = array();

     function getComposite()
    {
        return $this;
    }

    protected function units()
   {
        return $this->units;
    } 

    public function removeUnit(Unit $unit)
    {
        $this->units = array_udiff($this->units, array($unit), function($a, $b) {return ($a===$b)?0:1} );
    }

    public function addUnit(Unit $unit)
    {
        if(in_array($unit, $this->units, true))
        {
            return;
        }
        $this->units[] = $unit;
    }
}

如上所示:我们为组合对象添加了一个子抽象类,这个子抽象类中多了个方法getComposite,这个方法用于客户端识别是否为组合对象,如果是的话,返回这个 对象,如果不是,则返回null,这样客户端在调用aaUnit或者removeUnit方法前调用getComposite方法即可知道对象的类型,并作出适当的操作,完美的解决了透明模式中出现的问题。

但是这两种模式本身没有孰优孰劣,具体使用哪种,需要根据业务来区分。

需要担心组合模式的成本如果子类嵌套太多,可能一个循环就把系统搞崩了,所以这里给出使用组合模式的技巧:

1)需要在父集对象中将子类的属性值缓存下来,这样可以减少系统开销,即便如此,还需要保证缓存值不会过期,即需要实时更新过期缓存。

2)对象持久化上,组合模式不适合存储在关系型数据库中,因为这样随着系统嵌套的深度加大,sql查询的开销就会越大,这样更新添加和移除子对象时的系统开销就会比较大。不过组合模式中的对象关系适合存放在xml中,xml中树形结构和组合对象中的树形结构正好匹配。

好了,关于组合模式的个人理解就讲到这了,内容会不断更新,力求慢慢领悟各种模式的真谛。

时间: 2024-10-25 07:49:02

php中的组合模式的相关文章

组合模式(Composite Pattern)

转:http://www.cnblogs.com/doubleliang/archive/2011/12/27/2304104.html 简而言之,就是让所有的叶子节点执行相同的操作!!!!!!!!!!!!!!! 组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性. 有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构

组合模式之拼凑的美好

廊坊的风一如既往的在窗外刮着,天地间肆意地飘洒,纵情在一刹那,为何如今仅仅剩下风吹乱我的发,乱蓬蓬的,还是去超市逛逛吧,买吃的`(*∩_∩*)′,走进华联超市,热情的店员招呼着我,開始为我介绍,推荐各种各样商品,店员向我推荐了他们的会员卡,全场全部项目均八折,每逢节假日打五折,我心想那太划算了,并且他们总店,分店,加盟店都能够用,所以就办了张会员卡.今天我们的设计模式就从超市会员卡開始说起. 这个俨然就是我们设计模式中的组合模式----组合模式有时候又叫做部分-总体模式,它使我们树型结构的问题中

设计模式:组合模式(Composite)

将对象组合成属性结构以表示"部分-总体"的层次结构.组合使得用户和单个对象和组合对象的使用具有一致性. 组合模式设计的角色: 1. Component:是组合中的对象声明接口.在适当的情况下.实现全部类共同拥有接口的默认行为.声明一个接口用于訪问和管理Component. 2. Leaf:在组合中表示叶子节点对象.叶子节点没有子节点. 3. Composite:定义树枝节点行为.用来存储子部件.在Component接口中实现与子部件有关操作,如增加和删除等. 举个简单样例(树枝和叶子)

iOS设计模式——组合模式

何为组合模式? 组合模式让我们可以把相同基类型的对象组合到树状结构中,其中父节点包含同类型的子节点.换句话说,这种树状结构形成"部分--整体"的层次结构.什么是"部分--整体"的层次结构呢?它是既包含对象的组合又包含叶节点的单个对象的一种层次结构.每个组合体包含的其他节点,可以是叶节点或者其他组合体.这种关系在这个层次结构中递归重复.因为每个组合或叶节点有相同的基类型,同样的操作可应用于它们中的每一个,而不必在客户端作类型检查.客户端对组合与叶节点进行操作时可忽略它

管道过滤器模式(Pipe and Filter)与组合模式(修改)

转自:http://haolloyin.blog.51cto.com/1177454/348277 之前在 benjielin 前辈的博客中看到“管道过滤器(Pipe-And-Filter)模式(http://bj007.blog.51cto.com/1701577/345677)”,当时将文章中运用到的组合模式(Composite)与我刚刚写过的装饰模式(Decorator)和职责链模式(Chain of Responsibility)混为一谈,并希望用这后面两个模式进行代码实现,+_+ 现在

简明 组合模式(4.3)

桌面上太多东西,会显得杂乱,于是人们使用各种容器将东西加以整理.将一系列基本对象(叶子对象)组合到一个容器中,容器又可以进一步放到另一个容器中. 组合模式(Composite Pattern)通过组合将构件最终构成一个树形结构.在计算机领域,树形结构广泛存在,如文件系统.菜单系统.GUI.Java(数据结构)容器.XML文件等等.组合模式的要点是:叶子对象和各种容器能够统一地处理.封装容器和叶子对象的通用操作的概念,通常称为构件/组件/Component. 程序员通常喜欢用树形结构的词汇介绍组合

JS学习十九天----组合模式

组合模式 前言 我今天又看了一下我自己写的博客,排版咋能这么丑?还能再丑一点吗?!我看了看我同学的排版,那叫一个漂亮啊,我想起来了一句诗:排版写得好,老公回家早!这几天我在修改我的排版,如果大家有什么意见,欢迎来稿!谢谢. 正文 组合模式:把多个对象组成树状结构来表示局部与整体,使得用户可以一样的对待单个对象和对象的组合. 1.可以以相同的方法处理对象的集合与其中的特定子对象.组合对象与组合该对象的对象可实现同一批操作.对组合(Composite)对象执行的操作过程将向下传递到所有的组成对象,使

Android设计模式系列(1)--SDK源码之组合模式

Android中对组合模式的应用,可谓是泛滥成粥,随处可见,那就是View和ViewGroup类的使用.在android UI设计,几乎所有的widget和布局类都依靠这两个类.组合模式,Composite Pattern,是一个非常巧妙的模式.几乎所有的面向对象系统都应用到了组合模式. 1.意图将对象View和ViewGroup组合成树形结构以表示"部分-整体"的层次结构(View可以做为ViewGroup的一部分).组合模式使得用户对单个对象View和组合对象ViewGroup的使

junit组合模式应用

组合模式 定义: 将对象组合成树形结构以表示“部分-整体”的层次结构.Composite模式使得用户对单个对象和组合对象的使用具有一致性 构成: Component:这是一个抽象角色,它给参加组合的对象规定一个接口.这个角色给出共有的接口和默认的行为.其实就我们的Test接口,它定义出run方法 Composite:实现共有接口并维护一个测试用例的集合,它就是复合测试用例TestSuite Leaf:代表参加组合的对象,它没有下级子对象,仅定义出参加组合的原始对象的行为,其实就是单一的测试用例T