天天看點

設計模式 - 組合模式(Composite Pattern)簡介PHP 代碼示例

參考:http://terrylee.cnblogs.com/archive/2006/03/11/347919.html

簡介

樹狀結構中,對于枝節點和葉節點,接口不同,用戶端需要判斷處理的節點類型。

場景

對于規模比較大的公司,其組織架構一般是:總公司,下面有分公司和直屬部門(總公司的人事、财務、行政),分公司下面又有直屬部門(分公司的人事、财務、行政)和支公司,支公司下面是各個部門。

在用戶端程式中,需要判斷傳回對象的具體類型到底是公司還是部門。如果是公司,則需要遞歸處理。

這增加了用戶端程式與複雜元素内部結構之間的依賴。組合模式可以解決這種問題。

模式定義

組合模式:将對象組合成樹形結構以表示“部分-整體”的層次結構,使得使用者對單個對象群組合對象的使用具有一緻性。

組合模式模糊了樹型結構問題中簡單元素和複雜元素的概念,客戶程式可以跟處理簡單元素一樣來處理複雜元素,進而使得客戶程式與複雜元素的内部結構解耦。

模式特點

組合模式包含四個角色:

  • Component:對象聲明接口,聲明所有類共有的預設行為
  • Composite:有子節點的節點,存儲子節點并實作 Component 接口有關操作
  • Leaf:葉節點,沒有子節點,用于定義對象的基本行為
  • Client:客戶類
設計模式 - 組合模式(Composite Pattern)簡介PHP 代碼示例

組合模式可以不提供父對象的管理方法,但必須提供子對象的管理方法(add、remove 等)。

根據所實作接口的差別,組合模式包括兩種:

  • 透明組合模式:葉節點和枝節點接口統一。在 Component 中聲明所有用來管理子對象的方法(Add、Remove 等)。這樣實作 Component 接口的所有子類都具備了管理子對象的方法。問題很明顯,因為 Leaf 類本身不具備管理子對象的功能,是以實作的部分方法沒有意義。
  • 安全組合模式:葉節點和枝節點接口不統一。不在 Component 中聲明用來管理子對象的方法,而是在 Composite 聲明所有用來管理子類對象的方法。問題也很明顯,葉節點和枝節點将不具有相同的接口,用戶端需要進行判斷。

優點

  • 将客戶代碼與複雜的對象容器結構解耦,客戶代碼隻和抽象接口發生依賴關系
  • 透明組合模式的葉節點和枝節點有完全一緻的行為接口

缺點

  • 透明組合模式的葉節點中,部分接口是沒有意義的
  • 安全組合模式的葉節點和枝節點具有不同的接口,用戶端調用需要做相應的判斷

PHP 代碼示例

<?php

abstract class Component {
    protected $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public abstract function Add(Component $c);
    public abstract function Remove(Component $c);
    public abstract function Display(int $depth);
}

class Composite extends Component {
    private $children = array();

    public function Add(Component $c) {
        array_push($this->children, $c);
    }

    public function Remove(Component $c) {
        array_pop($this->children);
    }

    public function Display(int $depth) {
        echo '-' . $depth . '  ' . $this->name . "<br/>";

        foreach ($this->children as $component) {
            $component->Display($depth + );
        }
    }
}

class Leaf extends Component {
    public function Add(Component $c) {
        echo "Cannot add to a leaf" . "<br/>";
    }

    public function Remove(Component $c) {
        echo "Cannot remove from a leaf" . "<br/>";
    }

    public function Display(int $depth) {
        echo '-' . depth . $this->name . "<br/>";
    }
}

echo '<pre>';

$root = new Composite("root");
$root->Add(new Leaf("Leaf A"));
$root->Add(new Leaf("Leaf B"));

$comp = new Composite("Composite X");
$comp->Add(new Leaf("Leaf XA"));
$comp->Add(new Leaf("Leaf XB"));

$root->Add($comp);

$comp2 = new Composite("Composite XY");
$comp2->Add(new Leaf("Leaf XYA"));
$comp2->Add(new Leaf("Leaf XYB"));

$comp->Add($comp2);

$root->Add(new Leaf("Leaf C"));

print_r($root);

$leaf = new Leaf("Leaf D");
$root->Add($leaf);
$root->Remove($leaf);

$root->Display();
           

輸出:

Composite Object
(
    [children:Composite:private] => Array
        (
            [] => Leaf Object
                (
                    [name:protected] => Leaf A
                )

            [] => Leaf Object
                (
                    [name:protected] => Leaf B
                )

            [] => Composite Object
                (
                    [children:Composite:private] => Array
                        (
                            [] => Leaf Object
                                (
                                    [name:protected] => Leaf XA
                                )

                            [] => Leaf Object
                                (
                                    [name:protected] => Leaf XB
                                )

                            [] => Composite Object
                                (
                                    [children:Composite:private] => Array
                                        (
                                            [] => Leaf Object
                                                (
                                                    [name:protected] => Leaf XYA
                                                )

                                            [] => Leaf Object
                                                (
                                                    [name:protected] => Leaf XYB
                                                )

                                        )

                                    [name:protected] => Composite XY
                                )

                        )

                    [name:protected] => Composite X
                )

            [] => Leaf Object
                (
                    [name:protected] => Leaf C
                )

        )

    [name:protected] => root
)
-  root
-depthLeaf A
-depthLeaf B
-  Composite X
-depthLeaf XA
-depthLeaf XB
-  Composite XY
-depthLeaf XYA
-depthLeaf XYB
-depthLeaf C
           

繼續閱讀