本文實例講述了PHP設計模式:組合模式Composite。分享給大家供大家參考,具體如下:
1. 概述
在數據結構里面,樹結構是很重要,我們可以把樹的結構應用到設計模式里面。
例子1:就是多級樹形菜單。
例子2:文件和文件夾目錄
2.問題
我們可以使用簡單的對象組合成復雜的對象,而這個復雜對象有可以組合成更大的對象。我們可以把簡單這些對象定義成類,然后定義一些容器類來存儲這些簡單對象。客戶端代碼必須區別對象簡單對象和容器對象,而實際上大多數情況下用戶認為它們是一樣的。對這些類區別使用,使得程序更加復雜。遞歸使用的時候跟麻煩,而我們如何使用遞歸組合,使得用戶不必對這些類進行區別呢?
3. 解決方案
組合模式:將對象組合成樹形結構以表示“部分-整體”的層次結構。Composite使得用戶對單個對象和組合對象的使用具有一致性。
有時候又叫做部分-整體模式,它使我們樹型結構的問題中,模糊了簡單元素和復雜元素的概念,客戶程序可以向處理簡單元素一樣來處理復雜元素,從而使得客戶程序與復雜元素的內部結構解耦。
組合模式讓你可以優化處理遞歸或分級數據結構。有許多關于分級數據結構的例子,使得組合模式非常有用武之地。關于分級數據結構的一個普遍性的例子是你每次使用電腦時所遇到的:文件系統。文件系統由目錄和文件組成。每個目錄都可以裝內容。目錄的內容可以是文件,也可以是目錄。按照這種方式,計算機的文件系統就是以遞歸結構來組織的。如果你想要描述這樣的數據結構,那么你可以使用組合模式Composite。
4. 組合模式的分類
1) 將管理子元素的方法定義在Composite類中
2) 將管理子元素的方法定義在Component接口中,這樣Leaf類就需要對這些方法空實現。
5. 適用性
以下情況下適用Composite模式:
1).你想表示對象的部分-整體層次結構
2).你希望用戶忽略組合對象與單個對象的不同,用戶將統一地使用組合結構中的所有對象。
6. 結構

典型的Composite對象結構如下圖所示:

7. 構建模式的組成
抽象構件角色(component):是組合中的對象聲明接口,在適當的情況下,實現所有類共有接口的默認行為。聲明一個接口用于訪問和管理Component子部件。
這個接口可 以用來管理所有的子對象。(可選)在遞歸結構中定義一個接口,用于訪問一個父部件,并在合適的情況下實現它。
樹葉構件角色(Leaf):在組合樹中表示葉節點對象,葉節點沒有子節點。并在組合中定義圖元對象的行為。
樹枝構件角色(Composite):定義有子部件的那些部件的行為。存儲子部件。在Component接口中實現與子部件有關的操作。
客戶角色(Client):通過component接口操縱組合部件的對象。
8. 效果
1) • 定義了包含基本對象和組合對象的類層次結構 基本對象可以被組合成更復雜的組合對象,而這個組合對象又可以被組合,這樣不斷的遞歸下去。客戶代碼中,任何用到 基本對象的地方都可以使用組合對象。
2) • 簡化客戶代碼 客戶可以一致地使用組合結構和單個對象。通常用戶不知道 (也不關心)處理的是一個葉節點還是一個組合組件。這就簡化了客戶代碼 , 因為在定義組合的那些類中不需要寫一些充斥著選擇語句的函數。
3) • 使得更容易增加新類型的組件 新定義的Composite或Leaf子類自動地與已有的結構和客戶代碼一起工作,客戶程序不需因新的Component類而改變。
4) • 使你的設計變得更加一般化 容易增加新組件也會產生一些問題,那就是很難限制組合中的組件。有時你希望一個組合只能有某些特定的組件。使用Composite時,你不能依賴類型系統施加這些約束,而必須在運行時刻進行檢查。
9. 實現
比較經典的例子是樹形菜單。多級展示,這個菜單可以無限增加節點;例外就是文件遍歷等等。
?php
/**
* 組合模式
*
* @author guisu
* @version 1.0
* 組合模式:樹形菜單
*
* 將對象組合成樹形結構以表示"部分-整體"的層次結構,使得客戶對單個對象和復合對象的使用具有一致性
*/
/**
* 抽象構件角色(component)
*
*/
abstract class MenuComponent
{
public function add($component){}
public function remove($component){}
public function getName(){}
public function getUrl(){}
public function displayOperation(){}
}
/**
* 樹枝構件角色(Composite)
*
*/
class MenuComposite extends MenuComponent
{
private $_items = array();
private $_name = null;
private $_align = '';
public function __construct($name) {
$this->_name = $name;
}
public function add($component) {
$this->_items[$component->getName()] = $component;
}
public function remove($component) {
$key = array_search($component,$this->_items);
if($key !== false) unset($this->_items[$key]);
}
public function getItems() {
return $this->_items;
}
public function displayOperation() {
static $align = '|';
if($this->getItems()) {
//substr($align, strpos($align,));
$align .= ' _ _ ';
}else{
$align .='';
}
echo $this->_name, " br/>";
foreach($this->_items as $name=> $item) {
echo $align;
$item->displayOperation();
}
}
public function getName(){
return $this->_name;
}
}
/**
*樹葉構件角色(Leaf)
*
*/
class ItemLeaf extends MenuComponent
{
private $_name = null;
private $_url = null;
//public $_align = '----';
public function __construct($name,$url)
{
$this->_name = $name;
$this->_url = $url;
}
public function displayOperation()
{
echo 'a href="', $this->_url, '" rel="external nofollow" >' , $this->_name, '/a>br/>';
}
public function getName(){
return $this->_name;
}
}
class Client
{
public static function displayMenu()
{
$subMenu1 = new MenuComposite("submenu1");
$subMenu2 = new MenuComposite("submenu2");
$subMenu3 = new MenuComposite("submenu3");
$subMenu4 = new MenuComposite("submenu4");
$subMenu5 = new MenuComposite("submenu5");
/*
$item1 = new ItemLeaf("sohu","www.163.com");
$item2 = new ItemLeaf("sina","www.sina.com");
$subMenu4 = new MenuComposite("submenu4");
$subMenu1->add($subMenu4);
$subMenu4->add($item1);
$subMenu4->add($item2);
*/
$item3 = new ItemLeaf("baidu","www.baidu.com");
$item4 = new ItemLeaf("google","www.google.com");
$subMenu2->add($item3);
$subMenu2->add($item4);
$allMenu = new MenuComposite("AllMenu");
$allMenu->add($subMenu1);
$allMenu->add($subMenu2);
$allMenu->add($subMenu3);
$subMenu3->add($subMenu4);
$subMenu4->add($subMenu5);
$allMenu->displayOperation();
}
}
// 創建menu
Client::displayMenu();
?>
10. 組合模式和其他相關模式
1)裝飾模式(Decorator模式)經常與Composite模式一起使用。當裝飾和組合一起使用時,它們
通常有一個公共的父類。因此裝飾必須支持具有 Add、Remove和GetChild 操作的Component接口。
2)Flyweight模式讓你共享組件,但不再能引用他們的父部件。
3)(迭代器模式)Itertor可用來遍歷Composite。
4)(觀察者模式)Visitor將本來應該分布在Composite和L e a f類中的操作和行為局部化。
11. 總結
組合模式解耦了客戶程序與復雜元素內部結構,從而使客戶程序可以向處理簡單元素一樣來處理復雜元素。
如果你想要創建層次結構,并可以在其中以相同的方式對待所有元素,那么組合模式就是最理想的選擇。
更多關于PHP相關內容感興趣的讀者可查看本站專題:《php面向對象程序設計入門教程》、《PHP數組(Array)操作技巧大全》、《PHP基本語法入門教程》、《PHP運算與運算符用法總結》、《php字符串(string)用法總結》、《php+mysql數據庫操作入門教程》及《php常見數據庫操作技巧匯總》
希望本文所述對大家PHP程序設計有所幫助。
您可能感興趣的文章:- PHP設計模式(九)外觀模式Facade實例詳解【結構型】
- PHP設計模式(八)裝飾器模式Decorator實例詳解【結構型】
- PHP設計模式(六)橋連模式Bridge實例詳解【結構型】
- PHP設計模式(五)適配器模式Adapter實例詳解【結構型】
- PHP設計模式(四)原型模式Prototype實例詳解【創建型】
- PHP設計模式(三)建造者模式Builder實例詳解【創建型】
- PHP設計模式(一)工廠模式Factory實例詳解【創建型】
- 深入分析PHP設計模式