DEV Community

菜皮日记
菜皮日记

Posted on

结构型设计模式-组合(对象树) Composite

简介

组合模式又叫对象树,将对象按照树形结构串起来,呈现出局部和整体相同的特性。

树中每个节点都由两部分组成,首先节点有自己的业务数据,其次节点内可以含有子节点集合。

比如盒子中可以放物品,也可以放其他小盒子,小盒子里又可以放物品和其他更小的盒子。

当计算盒子的物品价格时,只需要将盒子里本身的物品价格,加上小盒子里所有物品价格即可,递归处理。

类图

角色

  • 抽象节点 Component

    定义一个节点的基础方法,如内部添加子节点等

  • 具体节点之叶子节点 Leaf

    叶子节点没有子节点

  • 具体节点之非叶子节点 Composite/Container

    非叶子节点,可添加子节点

或者也可以不区分是否是叶子节点,都视为节点即可

类图

图中显示,Leaf 和 Composite 都实现 Component 接口。

Composite 可添加或删除子节点,execute 则指派调用子节点的 execute 方法。

Leaf 的 execute 是真正执行逻辑的地方

类图

代码

<?php

abstract class Component
{
    protected $parent;

    public function setParent(Component $parent)
    {
        $this->parent = $parent;
    }

    public function getParent(): Component
    {
        return $this->parent;
    }

    public function add(Component $component): void { }

    public function remove(Component $component): void { }

    public function isComposite(): bool
    {
        return false;
    }

    abstract public function operation(): string;
}

class Leaf extends Component
{
    public function operation(): string
    {
        return "Leaf";
    }
}

class Composite extends Component
{
    protected $children;

    public function __construct()
    {
        $this->children = new \SplObjectStorage();
    }

    public function add(Component $component): void
    {
        $this->children->attach($component);
        $component->setParent($this);
    }

    public function remove(Component $component): void
    {
        $this->children->detach($component);
        $component->setParent(null);
    }

    public function isComposite(): bool
    {
        return true;
    }

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

// 只有一个叶子节点
$simple = new Leaf();
echo "Client: I've got a simple component:\n";
clientCode($simple);

echo "\n";

// 构建一个tree
$tree = new Composite();
$branch1 = new Composite();
$branch1->add(new Leaf());
$branch1->add(new Leaf());
$branch2 = new Composite();
$branch2->add(new Leaf());
$tree->add($branch1);
$tree->add($branch2);
echo "Client: Now I've got a composite tree:\n";
clientCode($tree);

// 合并两个tree
function clientCode2(Component $component1, Component $component2)
{
    if ($component1->isComposite()) {
        $component1->add($component2);
    }
    echo "RESULT: " . $component1->operation();
}

echo "\n";
echo "Client: I don't need to check the components classes even when managing the tree:\n";
clientCode2($tree, $simple);
Enter fullscreen mode Exit fullscreen mode

output:

Client: I've got a simple component:
RESULT: Leaf
Client: Now I've got a composite tree:
RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf))
Client: I don't need to check the components classes even when managing the tree:
RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf)+Leaf)
Enter fullscreen mode Exit fullscreen mode

AWS GenAI LIVE image

Real challenges. Real solutions. Real talk.

From technical discussions to philosophical debates, AWS and AWS Partners examine the impact and evolution of gen AI.

Learn more

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay