15、PHP 设计模式-组合模式

组合模式

组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。掌握组合模式的重点是要理解清楚 “部分/整体” 还有 ”单个对象“ 与 “组合对象” 的含义。

模式结构

  • Component :组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。
  • Leaf:叶子对象。叶子结点没有子结点。
  • Composite:容器对象,定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(add)和删除(remove)等。

结构图

 

PHP代码实现

<?php

// 组件接口声明了组合中简单和复杂对象的通用操作
interface Component {
    public function operation(): string;
}

// 叶子组件代表组合的末端对象。一个叶子对象没有子对象。
// 通常是这些对象执行实际的工作,而复合对象只是委托给它们的子组件。
class Leaf implements Component {
    private $name;

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

    public function operation(): string {
        return "Leaf " . $this->name . " performs an operation.\n";
    }
}

// 容器组件包含复杂组件,可以包含叶子节点或其他容器节点。
class Composite implements Component {
    protected $children = [];

    public function add(Component $component): void {
        $this->children[] = $component;
    }

    public function remove(Component $component): void {
        $this->children = array_filter($this->children, function ($child) use ($component) {
            return $child !== $component;
        });
    }

    public function operation(): string {
        $results = [];
        foreach ($this->children as $child) {
            $results[] = $child->operation();
        }
        return "Branch(" . implode("+", $results) . ")";
    }
}

// 客户端代码以统一的方式工作与所有组件
function clientCode(Component $component) {
    // ...
    echo "RESULT: " . $component->operation();
    // ...
}

// 这样可以构建简单的组件
$leaf = new Leaf("Leaf 1");
echo "Client: I've got a simple component:\n";
clientCode($leaf);
echo "\n\n";

// 以及更复杂的组合
$tree = new Composite();
$branch1 = new Composite();
$branch1->add(new Leaf("Leaf 2"));
$branch1->add(new Leaf("Leaf 3"));

$branch2 = new Composite();
$branch2->add(new Leaf("Leaf 4"));

$tree->add($branch1);
$tree->add($branch2);

echo "Client: Now I've got a composite tree:\n";
clientCode($tree);
echo "\n\n";

// 你可以管理组合对象的生命周期,就像你是管理一个单一组件一样
echo "Client: I don't need to check the components classes even when managing the tree:\n";
clientCode($tree);