[设计模式] 组合模式

组合模式用来解决整体和部分可以一致对待的问题

比如说 文件夹 和其下的 文件;
可以复制文件也可以复制整个文件夹;

组合模式是将对象组合成树形结构以表示整体和部分的层次结构;

可以方便的增加节点;

说明

运用tp5框架进行测试;
这里选用的层次结构是:唐朝的三省六部制
【设计模式】组合模式

代码

1、CentralSystem.php文件(抽象类)
<?php
namespace app\composite\controller;

/**
 * Class CentralSystem  中央官制抽象类,其子类必须实现抽象方法
 */
abstract  class CentralSystem
{
    // 当前类名字
    protected $name;

    // 构造函数,初始化$name
    public function __construct($name)
    {
        $this->name = $name;
    }

    // 获得类名字
    public function getName()
    {
        return $this->name;
    }

    // 添加子节点
    abstract public function add(CentralSystem $centralSystem);

    // 移除子节点
    abstract public function remove(CentralSystem $centralSystem);

    // 循环当前节点的子节点
    abstract public function show($deep);
}
2、Emperor.php文件 与 Province.php文件 一样 (皇帝类和三省类)

可以只写一个Emperor文件,不用同我一样,我就是纠结症犯了

<?php
namespace app\composite\controller;
use think\Exception;

/**
 * Class Emperor 皇帝类,相当于树的根节点root
 */
class Emperor extends CentralSystem
{
    // 存放其子节点
    protected $office = [];

    /**
     * @param CentralSystem $centralSystem  添加子节点,将子节点放在数组
     * @throws Exception
     */
    public function add(CentralSystem $centralSystem)
    {
        // 获取新节点的名字
        $office_name = $centralSystem->getName();

        if (in_array($office_name, $this->office)) {
            throw new Exception($office_name . '节点已经存在');
        } else {
            $this->office[$office_name] = $centralSystem;
        }
    }

    /**
     * @param CentralSystem $centralSystem 移除子节点,将子节点从数组中移除
     * @throws Exception
     */
    public function remove(CentralSystem $centralSystem)
    {
        // 获取新节点的名字
        $office_name = $centralSystem->getName();

        if (in_array($office_name, $this->office)) {
            unset($this->office[$office_name]);
        } else {
            throw new Exception($office_name . '节点不存在');
        }
    }

    /**
     * @param int $deep 重复字符'-'的次数
     */
    public function show($deep = 0)
    {
        echo str_repeat('-', $deep) . $this->name;
        echo "</br>";
        // 循环子节点的 节点数组$office
        foreach ($this->office as $item) {
            $item->show($deep + 4);
        }
    }
}
3、Ministries.php文件 (六部类)
<?php
namespace app\composite\controller;

class Ministries extends CentralSystem
{
    /**
     * @param CentralSystem $centralSystem  叶子节点,没有子节点
     */
    public function add(CentralSystem $centralSystem)
    {
        echo "叶子节点不能添加子节点";
    }

    public function remove(CentralSystem $centralSystem)
    {
        echo "叶子节点不能移除子节点";
    }

    /**
     * @param int $deep 字符'-'重复的次数
     */
    public function show($deep = 0)
    {
        echo str_repeat('-', $deep) . $this->name. "</br>";
    }
}
4、CompositeTest.php 测试文件
<?php
namespace app\composite\controller;

/**
 * Class CompositeTest  组合模式测试----唐朝三省六部制
 */
class CompositeTest
{
    public function test()
    {
        // 唐太宗相当于根节点root
        $emperor = new Emperor('唐太宗');
        // 唐太宗下的三个子节点:门下省、尚书省、中书省
        $emperor->add(new Province('门下省'));
        $emperor->add(new Province('中书省'));
        $shangshu = new Province('尚书省');     // 这里单独赋值是因为“尚书省”要另外添加子节点
        $emperor->add($shangshu);

        // 尚书省添加六部
        $shangshu->add(new Ministries('吏部'));
        $shangshu->add(new Ministries('户部'));
        $shangshu->add(new Ministries('礼部'));
        $shangshu->add(new Ministries('兵部'));
        $shangshu->add(new Ministries('刑部'));
        $shangshu->add(new Ministries('工部'));

        // 循环唐太宗的子节点数组,其子节点又有自己的子节点。
        $emperor->show();
    }
}

测试结果

【设计模式】组合模式

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 2

这不是装饰模式吗?

4年前 评论

@Imuyu 可以看下这个https://blog.csdn.net/itpinpai/article/details/51567511

4年前 评论
Imuyu 4年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!