定義: 組合模式(Composite):將對象組合成樹形結構以表示“部分-整體”的層次結構。組合模式使得用戶對單個對象和組合對象的使用具有一致性。當你發現需求中是體現部分與整體層次的結構時,以及你希望用戶可以忽略組合對象與單個對象的不同,統一的使用組合結構中的所有對象時,就應該考慮用組合模式了。 實 ...
定義:
組合模式(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