定義:
組合模式(Composite):將對象組合成樹形結構以表示“部分-整體”的層次結構。組合模式使得用戶對單個對象和組合對象的使用具有一致性。當你發現需求中是體現部分與整體層次的結構時,以及你希望用戶可以忽略組合對象與單個對象的不同,統一的使用組合結構中的所有對象時,就應該考慮用組合模式了。
實現方式:
1、透明方式:葉節點和枝節點對於外界沒有什麼區別,它們具備完全一致的行爲接口,問題則是葉節點會有冗餘方法。
2、安全方式:葉節點中的冗餘代碼不實現,問題則是由於不夠透明,所以葉節點和枝節點將不具有相同的接口,客戶端的調用需要做相應的判斷,帶來了不便。
代碼實例:
一、透明方式實現:
// 1、抽象類Component.php
/**
* 包含葉節點和枝節點方法的抽象類
* Class Component
*/
abstract class Component
{
/**
* @var
*/
protected $name;
/**
* Component constructor.
* @param $name
*/
public function __construct($name)
{
$this->name = $name;
}
/**
* 添加葉節點或枝節點
* @param Component $component
* @return mixed
*/
abstract public function add(Component $component);
/**
* @param $depth
* @return mixed
*/
abstract public function display($depth);
}
// 2、枝節點Composite.php
/**
* 枝節點
* Class Composite
*/
class Composite extends Component
{
/**
* @var array
*/
protected $children = [];
/**
* @param Component $component
* @return mixed|void
*/
public function add(Component $component)
{
// TODO: Implement add() method.
$this->children[] = $component;
}
public function display($depth)
{
// TODO: Implement display() method.
$nameStr = str_repeat('-', $depth) . $this->name . '<br>';
foreach ($this->children as $component) {
$nameStr .= $component->display($depth + 2);
}
return $nameStr;
}
}
// 3、葉節點Leaf.php
/**
* 葉節點
* Class Leaf
*/
class Leaf extends Component
{
/**
* 葉節點不需要添加子節點,但爲了保持葉節點和枝節點一致,代碼冗餘,透明方式
* @param Component $component
* @return mixed|string
*/
public function add(Component $component)
{
// TODO: Implement add() method.
return '葉節點不能添加子節點' . '<br>';
}
public function display($depth)
{
// TODO: Implement display() method.
return str_repeat('-', $depth) . $this->name . '<br>';
}
}
調用:
// 生成樹根root,根上長出兩葉LeafA和LeafB
$root = new Composite("root");
$root->add(new Leaf("Leaf A"));
$root->add(new Leaf("Leaf B"));
// 根上長出分支 CompositeX,分支上也有兩葉LeafXA和LeafXB
$comp = new Composite("Composite X");
$comp->add(new Leaf("Leaf XA"));
$comp->add(new Leaf("Leaf XB"));
$root->add($comp);
// 在CompositeX分支上再長出分支CompositeXY,分支上也有兩葉LeafXYA和LeafXYB
$comp2 = new Composite("Composite XY");
$comp2->add(new Leaf("Leaf XYA"));
$comp2->add(new Leaf("Leaf XYB"));
$comp->add($comp2);
echo $root->display(2);
結果:
--root
----Leaf A
----Leaf B
----Composite X
------Leaf XA
------Leaf XB
------Composite XY
--------Leaf XYA
--------Leaf XYB
二、安全方式實現:
// 1、抽象類Component.php
/**
* 包含葉節點和枝節點方法的抽象類
* Class Component
*/
abstract class Component
{
/**
* @var
*/
protected $name;
/**
* Component constructor.
* @param $name
*/
public function __construct($name)
{
$this->name = $name;
}
/**
* @param $depth
* @return mixed
*/
abstract public function display($depth);
}
// 2、枝節點Composite.php
/**
* 枝節點
* Class Composite
*/
class Composite extends Component
{
/**
* @var array
*/
protected $children = [];
/**
* @param Component $component
* @return mixed|void
*/
public function add(Component $component)
{
// TODO: Implement add() method.
$this->children[] = $component;
}
public function display($depth)
{
// TODO: Implement display() method.
$nameStr = str_repeat('-', $depth) . $this->name . '<br>';
foreach ($this->children as $component) {
$nameStr .= $component->display($depth + 2);
}
return $nameStr;
}
}
// 3、葉節點Leaf.php
/**
* 葉節點
* Class Leaf
*/
class Leaf extends Component
{
public function display($depth)
{
// TODO: Implement display() method.
return str_repeat('-', $depth) . $this->name . '<br>';
}
}
調用:
// 生成樹根root,根上長出兩葉LeafA和LeafB
$root = new Composite("root");
$root->add(new Leaf("Leaf A"));
$root->add(new Leaf("Leaf B"));
// 根上長出分支 CompositeX,分支上也有兩葉LeafXA和LeafXB
$comp = new Composite("Composite X");
$comp->add(new Leaf("Leaf XA"));
$comp->add(new Leaf("Leaf XB"));
$root->add($comp);
// 在CompositeX分支上再長出分支CompositeXY,分支上也有兩葉LeafXYA和LeafXYB
$comp2 = new Composite("Composite XY");
$comp2->add(new Leaf("Leaf XYA"));
$comp2->add(new Leaf("Leaf XYB"));
$comp->add($comp2);
echo $root->display(2);
結果:
--root
----Leaf A
----Leaf B
----Composite X
------Leaf XA
------Leaf XB
------Composite XY
--------Leaf XYA
--------Leaf XYB