19 05 2020

组合模式

模式定义

组合模式(Composite),有时候又叫做部分-整体模式,用于将对象组合成树形结构以表示“部分-整体”的层次关系。组合模式使得用户对单个对象和组合对象的使用具有一致性。


组合模式的优势

使我们在树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。  


组合模式让你可以优化处理递归或分级数据结构。 


代码示例

Composite\CompanyBase.class.php
<?php

namespace Composite;

abstract class CompanyBase
{
    protected $name;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }

    abstract function add(CompanyBase $c);

    abstract function remove(CompanyBase $c);

    abstract function show($deep);

    abstract function work($deep);
}


Composite\Company.class.php
<?php

namespace Composite;

class Company extends CompanyBase
{
    protected $item = [];

    public function add(CompanyBase $c)
    {
        $nodeName = $c->getName();

        if(!isset($this->item[$nodeName])){
            $this->item[$nodeName] = $c;
        } else {
            throw new Exception("该节点已存在,节点名称:" . $nodeName);
        }
    }

    function remove(CompanyBase $c)
    {
        $nodeName = $c->getName();

        if(isset($this->item[$nodeName])) {
            unset($this->item[$nodeName]);
        } else {
            throw new Exception("该节点已存在,节点名称:" . $nodeName);
        }
    }

    function show($deep = 0)
    {
        echo str_repeat("-", $deep) . $this->name;
        echo "\n";

        foreach ($this->item as $value){
            $value->show($deep + 4);
        }
    }

    function work($deep = 0)
    {
        foreach ($this->item as $value){
            echo str_repeat("    ", $deep) . "[{$this->name}]\n";
            $value->work($deep + 2);
        }
    }
}


Composite\HumanResources.class.php
<?php

namespace Composite;

class HumanResources extends CompanyBase
{

    function add(CompanyBase $c)
    {
        throw new Exception("该节点不能增加节点");
    }

    function remove(CompanyBase $c)
    {
        throw new Exception("该节点下无子节点");
    }

    function show($deep = 0)
    {
        echo str_repeat("-",$deep).$this->name;
        echo "\n";
    }

    function work($deep = 0)
    {
        echo str_repeat("    ",$deep)."人力资源部门的工作是为公司招聘人才";
        echo "\n";
    }
}


Composite\Commerce.class.php
<?php

namespace Composite;

class Commerce extends CompanyBase
{

    function add(CompanyBase $c)
    {
        throw new Exception("该节点下不能增加节点");
    }

    function remove(CompanyBase $c)
    {
        throw new Exception("该节点下无子节点");
    }

    function show($deep = 0)
    {
        echo str_repeat("-",$deep).$this->name;
        echo "\n";
    }

    function work($deep = 0)
    {
        echo str_repeat("    ",$deep)."商务部门的工作是为公司赚取利润";
        echo "\n";
    }
}


Composite\CompositeTest.php
<?php
spl_autoload_register(function ($className){
    $className = str_replace("\\", "/", $className);
    include $className . ".class.php";
});

use Composite\Company;
use Composite\HumanResources;
use Composite\Commerce;

$company = new Company("公司");
$human = new HumanResources("人力资源部");
$commerce = new Commerce("商务部");

$company->add($human);
$company->add($commerce);

$company1 = new Company("分公司1");
$company1->add($human);
$company1->add($commerce);
$company->add($company1);

$company2 = new Company("分公司2");
$company2->add($human);
$company2->add($commerce);
$company->add($company2);

$company->show();
echo "\n\n";
$company->work();


测试示例:

php Composite/CompositeTest.php 

输出:
公司
----人力资源部
----商务部
----分公司1
--------人力资源部
--------商务部
----分公司2
--------人力资源部
--------商务部


[公司]
        人力资源部门的工作是为公司招聘人才
[公司]
        商务部门的工作是为公司赚取利润
[公司]
        [分公司1]
                人力资源部门的工作是为公司招聘人才
        [分公司1]
                商务部门的工作是为公司赚取利润
[公司]
        [分公司2]
                人力资源部门的工作是为公司招聘人才
        [分公司2]
                商务部门的工作是为公司赚取利润


总结

组合模式,就是在一个对象中包含其他对象,这些被包含的对象可能是终点对象(不再包含别的对象),也有可能是非终点对象(其内部还包含其他对象,或叫组对象),我们将对象称为节点,即一个根节点包含许多子节点,这些子节点有的不再包含子节点,而有的仍然包含子节点,以此类推。很明显,这是树形结构,终结点叫叶子节点,非终节点(组节点)叫树枝节点,第一个节点叫根节点。同时也类似于文件目录的结构形式:文件可称之为终节点,目录可称之为非终节点(组节点)。




代码地址:https://github.com/798256478/design-patterns/tree/master/Composite