设计模式 - 组合模式(Composite Pattern)

it2022-05-09  53

参考:http://terrylee.cnblogs.com/archive/2006/03/11/347919.html

简介

树状结构中,对于枝节点和叶节点,接口不同,客户端需要判断处理的节点类型。

场景

对于规模比较大的公司,其组织架构一般是:总公司,下面有分公司和直属部门(总公司的人事、财务、行政),分公司下面又有直属部门(分公司的人事、财务、行政)和支公司,支公司下面是各个部门。

在客户端程序中,需要判断返回对象的具体类型到底是公司还是部门。如果是公司,则需要递归处理。

这增加了客户端程序与复杂元素内部结构之间的依赖。组合模式可以解决这种问题。

模式定义

组合模式:将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。

组合模式模糊了树型结构问题中简单元素和复杂元素的概念,客户程序可以跟处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。

模式特点

组合模式包含四个角色:

Component:对象声明接口,声明所有类共有的默认行为Composite:有子节点的节点,存储子节点并实现 Component 接口有关操作Leaf:叶节点,没有子节点,用于定义对象的基本行为Client:客户类

组合模式可以不提供父对象的管理方法,但必须提供子对象的管理方法(add、remove 等)。

根据所实现接口的区别,组合模式包括两种:

透明组合模式:叶节点和枝节点接口统一。在 Component 中声明所有用来管理子对象的方法(Add、Remove 等)。这样实现 Component 接口的所有子类都具备了管理子对象的方法。问题很明显,因为 Leaf 类本身不具备管理子对象的功能,所以实现的部分方法没有意义。安全组合模式:叶节点和枝节点接口不统一。不在 Component 中声明用来管理子对象的方法,而是在 Composite 声明所有用来管理子类对象的方法。问题也很明显,叶节点和枝节点将不具有相同的接口,客户端需要进行判断。

优点

将客户代码与复杂的对象容器结构解耦,客户代码只和抽象接口发生依赖关系透明组合模式的叶节点和枝节点有完全一致的行为接口

缺点

透明组合模式的叶节点中,部分接口是没有意义的安全组合模式的叶节点和枝节点具有不同的接口,客户端调用需要做相应的判断

PHP 代码示例

<?php abstract class Component { protected $name; public function __construct($name) { $this->name = $name; } public abstract function Add(Component $c); public abstract function Remove(Component $c); public abstract function Display(int $depth); } class Composite extends Component { private $children = array(); public function Add(Component $c) { array_push($this->children, $c); } public function Remove(Component $c) { array_pop($this->children); } public function Display(int $depth) { echo '-' . $depth . ' ' . $this->name . "<br/>"; foreach ($this->children as $component) { $component->Display($depth + 2); } } } class Leaf extends Component { public function Add(Component $c) { echo "Cannot add to a leaf" . "<br/>"; } public function Remove(Component $c) { echo "Cannot remove from a leaf" . "<br/>"; } public function Display(int $depth) { echo '-' . depth . $this->name . "<br/>"; } } echo '<pre>'; $root = new Composite("root"); $root->Add(new Leaf("Leaf A")); $root->Add(new Leaf("Leaf B")); $comp = new Composite("Composite X"); $comp->Add(new Leaf("Leaf XA")); $comp->Add(new Leaf("Leaf XB")); $root->Add($comp); $comp2 = new Composite("Composite XY"); $comp2->Add(new Leaf("Leaf XYA")); $comp2->Add(new Leaf("Leaf XYB")); $comp->Add($comp2); $root->Add(new Leaf("Leaf C")); print_r($root); $leaf = new Leaf("Leaf D"); $root->Add($leaf); $root->Remove($leaf); $root->Display(1);

输出:

Composite Object ( [children:Composite:private] => Array ( [0] => Leaf Object ( [name:protected] => Leaf A ) [1] => Leaf Object ( [name:protected] => Leaf B ) [2] => Composite Object ( [children:Composite:private] => Array ( [0] => Leaf Object ( [name:protected] => Leaf XA ) [1] => Leaf Object ( [name:protected] => Leaf XB ) [2] => Composite Object ( [children:Composite:private] => Array ( [0] => Leaf Object ( [name:protected] => Leaf XYA ) [1] => Leaf Object ( [name:protected] => Leaf XYB ) ) [name:protected] => Composite XY ) ) [name:protected] => Composite X ) [3] => Leaf Object ( [name:protected] => Leaf C ) ) [name:protected] => root ) -1 root -depthLeaf A -depthLeaf B -3 Composite X -depthLeaf XA -depthLeaf XB -5 Composite XY -depthLeaf XYA -depthLeaf XYB -depthLeaf C

转载于:https://www.cnblogs.com/kika/p/10851560.html


最新回复(0)