首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >php设计模式(十):组合模式(Composite)

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

作者头像
陈大剩博客
发布2023-04-27 14:33:49
发布2023-04-27 14:33:49
46600
代码可运行
举报
运行总次数:0
代码可运行

组合模式

组合模式又称:对象树、Object Tree、Composite,组合 是一种结构型设计模式,使用它将对组合成树状结构,并且能像使用独立对象一样使用它们。

问题

如果应用的核心模型能用树状结构表示,在应用中使用组合模式才有价值。

学过 Linux 的同学都知道,Linux 一切都是文件,那么 Linux 文件系统类型就有两类对象: 文件夹文件 。一个 文件夹 中可以包含多个 文件 或者几个较小的 文件夹 。这些 小文件夹 中同样可以包含一些 文件 或更小的 文件夹 ,以此类推。如果是我们来开发 Linux 文件系统,我们该如何做出文件结构呢?

打开所有文件夹, 找到每件文件, 然后 统计。这在真实世界中或许可行,但在程序中,并不能简单地使用循环语句来完成该工作。必须事先知道所有 文件夹文件 的类别,所有文件夹的嵌套层数以及其他繁杂的细节信息。因此, 直接计算极不方便, 甚至完全不可行。

解决方法

使用一个通用接口来与 文件夹文件 进行交互, 并且在该接口中声明一个统计子文件的方法。我们可以使用组合模式以递归方式处理文件夹对象树中的所有项目。递归出所有内部组成部分。

本例使用透明的组合模式,还有安全组合模式可用。

结构

Node:包含文件夹(树枝节点)和文件(叶子节点)方法的抽象类 Dir:文件夹(树枝节点)有子节点 File:文件(叶子节点)没有子节点

代码示例

抽象类容器类(节点类)

代码语言:javascript
代码运行次数:0
运行
复制
abstract class Node
{
    protected $name;


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

    /**
     * 增加节点
     * @return mixed
     * @author chendashengpc
     */
    abstract public function add(Node $node);

    /**
     * 删除节点
     * @return mixed
     * @author chendashengpc
     */
    abstract public function remove(Node $node);

    /**
     * 显示当前树
     * @param $level 树等级
     * @return mixed
     * @author chendashengpc
     */
    abstract public function display($level);
}

具体容器类(文件夹)

代码语言:javascript
代码运行次数:0
运行
复制
/**
 * 文件夹
 */
class Dir extends Node
{
    protected $children = [];

    public function add(Node $node)
    {
        if (isset($this->children[$node->name])) {
            throw new \Exception('请勿重复创建');
        }
        $this->children[$node->name] = $node;
    }

    public function remove(Node $node)
    {
        if (!isset($this->children[$node->name])) {
            throw new \Exception('请创建后再移除');
        }
        unset($this->children[$node->name]);
    }

    /**
     * 输出目录 [d] 为目录
     * @param $level
     * @return string
     * @author chendashengpc
     */
    public function display($level = '')
    {
        $nameStr = $level . '[d]' . $this->name . PHP_EOL;
        foreach ($this->children as $k => $v) {
            $nameStr .= $v->display($level . '--');
        }
        return $nameStr;
    }
}

叶节点类(文件)

代码语言:javascript
代码运行次数:0
运行
复制
/**
 * 文件类
 */
class File extends Node
{
    public function add(Node $node)
    {
        throw new \Exception('文件不能添加子节点');
    }

    public function remove(Node $node)
    {
        throw new \Exception('文件不能添加子节点');
    }

    /**
     * 输出文件 [-] 为文件
     * @param $level
     * @return string
     * @author chendashengpc
     */
    public function display($level = '')
    {
        return $level . '[-]' . $this->name . PHP_EOL;
    }
}

客户端代码

代码语言:javascript
代码运行次数:0
运行
复制
$designPatterns = new Dir('design patterns');
$readme = new File('README.md');

$designPatterns->add($readme);

/**
 * Composite 文件夹
 */
$composite = new Dir('Composite');
$node = new File('Node.php');
$file = new File('File.php');
$dir = new File('Dir.php');

$composite->add($node);
$composite->add($file);
$composite->add($dir);

$designPatterns->add($composite);
$composite->remove($dir);

/**
 * Singleton 文件夹
 */
$singleton = new Dir('Singleton');
$singletonFile = new File('Singleton.php');
$singleton->add($singletonFile);

/**
 * 测试文件夹
 */
$test = new Dir('test');
$testFile = new File('test-file');
$test->add($testFile);
$singleton->add($test);

$designPatterns->add($singleton);

echo $designPatterns->display();

输出

代码语言:javascript
代码运行次数:0
运行
复制
[d]design patterns
--[-]README.md
--[d]Composite
----[-]Node.php
----[-]File.php
--[d]Singleton
----[-]Singleton.php
----[d]test
------[-]test-file

UML

优缺点

优点

  • 可以利用递归机制更方便的使用复杂结合
  • 开闭原则。无需更改现有代码,你就可以在应用中添加新元素,使其成为对象树的一部分。

缺点

  • 对于功能差异较大的类,提供公共接口或许会有困难。 在特定情况下,需要过度一般化组件接口,使其变得令人难以理解。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-04-21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 组合模式
  • 问题
  • 解决方法
  • 结构
  • 代码示例
    • 抽象类容器类(节点类)
    • 具体容器类(文件夹)
    • 叶节点类(文件)
    • 客户端代码
  • UML
  • 优缺点
    • 优点
    • 缺点
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档