1. 程式人生 > 程式設計 >PHP設計模式(七)組合模式Composite例項詳解【結構型】

PHP設計模式(七)組合模式Composite例項詳解【結構型】

本文例項講述了PHP設計模式:組合模式Composite。分享給大家供大家參考,具體如下:

1. 概述

在資料結構裡面,樹結構是很重要,我們可以把樹的結構應用到設計模式裡面。

例子1:就是多級樹形選單。

例子2:檔案和資料夾目錄

2.問題

我們可以使用簡單的物件組合成複雜的物件,而這個複雜物件有可以組合成更大的物件。我們可以把簡單這些物件定義成類,然後定義一些容器類來儲存這些簡單物件。客戶端程式碼必須區別物件簡單物件和容器物件,而實際上大多數情況下使用者認為它們是一樣的。對這些類區別使用,使得程式更加複雜。遞迴使用的時候跟麻煩,而我們如何使用遞迴組合,使得使用者不必對這些類進行區別呢?

3. 解決方案

組合模式:將物件組合成樹形結構以表示“部分-整體”的層次結構。Composite使得使用者對單個物件和組合物件的使用具有一致性。

有時候又叫做部分-整體模式,它使我們樹型結構的問題中,模糊了簡單元素和複雜元素的概念,客戶程式可以向處理簡單元素一樣來處理複雜元素,從而使得客戶程式與複雜元素的內部結構解耦。

  組合模式讓你可以優化處理遞迴或分級資料結構。有許多關於分級資料結構的例子,使得組合模式非常有用武之地。關於分級資料結構的一個普遍性的例子是你每次使用電腦時所遇到的:檔案系統。檔案系統由目錄和檔案組成。每個目錄都可以裝內容。目錄的內容可以是檔案,也可以是目錄。按照這種方式,計算機的檔案系統就是以遞迴結構來組織的。如果你想要描述這樣的資料結構,那麼你可以使用組合模式Composite。

4. 組合模式的分類

1) 將管理子元素的方法定義在Composite類中
2) 將管理子元素的方法定義在Component介面中,這樣Leaf類就需要對這些方法空實現。

5. 適用性

以下情況下適用Composite模式:

1).你想表示物件的部分-整體層次結構

2).你希望使用者忽略組合物件與單個物件的不同,使用者將統一地使用組合結構中的所有物件。

6. 結構

PHP設計模式(七)組合模式Composite例項詳解【結構型】

典型的Composite物件結構如下圖所示:

PHP設計模式(七)組合模式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程式設計有所幫助。