一個公司是由每個工作的成員組成,每一個成員有不同的屬性(名字,職位,薪水),根據不同的等級,構成一個樹形的結構。總經理是這棵樹的根節點,因為他沒有上級,部門經理是樹枝節點,因為他既有上級也有下級,小嘍囉是葉節點,因為他是最底層的苦逼,沒有下級。現用組合模式將這個樹展示出來,類別圖:
代碼如下:
<?php abstract class Corp { private $name = ''; private $position = ''; private $salary = 0; public function __construct( $name, $position, $salary ) { $this->name = $name; $this->position = $position; $this->salary = $salary; } public function getInfo() { $return = "姓名:".$this->name."\t"; $return .= "职位:".$this->position."\t"; $return .= "薪水:".$this->salary."\n"; return $return; } } class Leaf extends Corp{ } class Branch extends Corp{ private $subordinateList = array(); public function addSubordinate(Corp $corp){ array_push($this->subordinateList, $corp); } public function getSubordinateList(){ return $this->subordinateList; } } $root = new Branch('马总','总经理',100000); $branch1 = new Branch('罗总','研发部门经理',20000); $branch2 = new Branch('高总','销售部门经理',80000); $leaf1 = new Leaf('张三','开发人员',7000); $leaf2 = new Leaf('李四','开发人员',8000); $leaf3 = new Leaf('二蛋','销售人员',10000); $leaf4 = new Leaf('狗子','销售人员',15000); $root->addSubordinate($branch1); $branch1->addSubordinate($leaf1); $branch1->addSubordinate($leaf2); $root->addSubordinate($branch2); $branch2->addSubordinate($leaf3); $branch2->addSubordinate($leaf4); function getTreeInfo($branch){ echo $branch->getInfo(); $subordinateList = $branch->getSubordinateList(); foreach ($subordinateList as $value) { if($value instanceof Branch){ getTreeInfo($value); }else{ echo $value->getInfo(); } } } getTreeInfo($root); ?>
運作結果:
姓名:馬總 職位:總經理 薪水:100000經理 薪水:20000
姓名:張三 職位:開發人員 薪水:7000
姓名:李四 職位:開發人員 薪水:8000
姓名:高總 職位:銷售部門經理 薪水:800000%職位:銷售人員 薪水:10000
姓名:狗子 職位:銷售人員 薪水:15000
[Finished in 0.1s]
組合模式的定義
組合模式也叫合成模式,也叫部分合成模式主要是用來描述部分與整體的關係。其定義為:將物件組合成樹狀結構以表示」部分-整體「的層次結構,使得使用者對單一物件和組合物件的使用具有一致性。組合模式主要由三個角色構成
1、Component抽象構件角色
定義參加組合物件的共有方法和屬性,可以定義一些預設的行為或屬性,例如範例中的Corp類別。
2、Leaf葉子構件
3、Composite樹枝構件
組合樹枝節點和葉子節點形成一個樹形結構
組合模式的優點
1、高層模組調用簡單
組合模式的優點
1、高層模組調用簡單
組合模式的優點
1、高層模組調用簡單
組合模式的優點
1、高層模組調用簡單
所有節點都是Component,局部和整體對呼叫者來說沒有任何區別,也就是說,高層模組不必關心自己處理的是單一物件還是整個組合結構,簡化了高層模組的程式碼。
2、節點自己增加
只要找到它的父節點就成,非常容易擴展,符合開閉原則。
組合模式的缺點組合模式有一個非常明顯的缺點,看到在場景類別中的定義,提到樹葉和樹枝使用時的定義了嗎?直接使用了實作類別!這在面向介面程式設計上是很不恰當的,與依賴代表團原則衝突,限制了介面中的影響範圍。
組合模式的使用場景
1、維護和展示部分-整體關係的場景,如樹形選單、文件、資料夾管理。
2、從一個整體中的能夠獨立出總價模組或功能的場景。
組合模式的注意事項
只要是樹形結構,就要考慮使用組合模式,這個一定要記住,只要是要體現局部和整體的關係的時候,而且這種關係還可能比較深,就應該考慮一下組合模式。
組合模式的擴展
1、真實的組合模式(略過)
2、透明的組合模式
例子中是安全的組合模式,透明模式是把用來組合的方法放到抽象類別中(略過)3、組合模式的遍歷例子中實現了樹的從上級向下級遍歷,如果現隨便選中一個葉節點,如何向上級做遍歷?其實也很簡單,只要在新增節點時設定其父節點既可,代碼如下:
<?php abstract class Corp { private $name = ''; private $position = ''; private $salary = 0; <strong>private $parent = null;</strong> public function __construct( $name, $position, $salary ) { $this->name = $name; $this->position = $position; $this->salary = $salary; } public function getInfo() { $return = "姓名:".$this->name."\t"; $return .= "职位:".$this->position."\t"; $return .= "薪水:".$this->salary."\n"; return $return; } <strong>public function setParent($parent){ $this->parent = $parent; } public function getParent(){ return $this->parent; }</strong> } class Leaf extends Corp{ } class Branch extends Corp{ private $subordinateList = array(); public function addSubordinate(Corp $corp){ <strong>$corp->setParent($this);</strong> array_push($this->subordinateList, $corp); } public function getSubordinateList(){ return $this->subordinateList; } } $root = new Branch('马总','总经理',100000); $branch1 = new Branch('罗总','研发部门经理',20000); $branch2 = new Branch('高总','销售部门经理',80000); $leaf1 = new Leaf('张三','开发人员',7000); $leaf2 = new Leaf('李四','开发人员',8000); $leaf3 = new Leaf('二蛋','销售人员',10000); $leaf4 = new Leaf('狗子','销售人员',15000); $root->addSubordinate($branch1); $branch1->addSubordinate($leaf1); $branch1->addSubordinate($leaf2); $root->addSubordinate($branch2); $branch2->addSubordinate($leaf3); $branch2->addSubordinate($leaf4); function getParentInfo($leaf){ echo $leaf->getInfo(); $parent = $leaf->getParent(); if($parent instanceof branch) getParentInfo($parent); } getParentInfo($leaf4); ?>
運作結果:
姓名:狗子 職位:銷售人員 薪水:150000
職位:銷售部門經理 薪水:80000🎜🎜姓名:馬總 職位:總經理 薪水:100000🎜🎜[Finished in 0.2s]🎜🎜 代碼中黑體部分為與上一例的區別。 🎜