陈大剩博客

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

  • 陈大剩
  • 2023-04-21 21:02:53
  • 755

组合模式

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

问题

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

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

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

解决方法

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

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

结构

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

代码示例

抽象类容器类(节点类)

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);
}

具体容器类(文件夹)

/**
 * 文件夹
 */
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;
    }
}

叶节点类(文件)

/**
 * 文件类
 */
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;
    }
}

客户端代码

$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();

输出

[d]design patterns
--[-]README.md
--[d]Composite
----[-]Node.php
----[-]File.php
--[d]Singleton
----[-]Singleton.php
----[d]test
------[-]test-file

UML

组合模式

新型结构

优缺点

优点

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

缺点

  • 对于功能差异较大的类,提供公共接口或许会有困难。 在特定情况下,需要过度一般化组件接口,使其变得令人难以理解。
分享到:
0

说点儿什么吧

头像

表情

本站由陈大剩博客程序搭建 | 湘ICP备2023000975号| Copyright © 2017 - 陈大剩博客 | 本站采用创作共用版权:CC BY-NC 4.0

站长统计| 文章总数[115]| 评论总数[9]| 登录用户[22]| 时间点[118]

logo

登入

社交账号登录