C#面向對象設計模式縱橫談 學習筆記9 Composite 組合(結構型模式)

在我們開發過程中,我們可能需要用到一種設計,一個容器可以包含一個對象,並且也可以包含一個容器,我們需要通過一個接口或一個抽象類來表示這個容器或對象,也就是說容器或對象是同一總類型,但是包含關係,也就是說我們需要用一種模式來實現多叉樹的結構。節點可以包含字節點,也可以包含子項。

我們可以通過Composite模式來實現。

首先看看Composite模式的動機:

如何將"客戶代碼與複雜的對象容器結構"解耦?讓對象容器自己來實現自身的複雜結構,從而使得客戶代碼就像處理簡單對象一樣來處理複雜的對象容器?

Composite模式的意圖:

將對象組合成樹形結構以表示"部分-整體"的層次結構。Composite使得用戶對單個對象和組合對象的使用具有一致性。

看看實現的代碼

public interface IBox
{
    
void Process();
    
void Add(IBox box);
    
void Remove(IBox box);
}

這是一個接口,它定義了對象和容器應該需要實現的方法,在這個接口裏Add和Remove方法是對象不需要實現的,可以在實現這兩個方法是拋出異常,或者爲空方法。

public class SingleBox : IBox
{
    
public void Process
    
{
        
    }


    
public void Add(IBox box)
    
{
        
throw new Exception();
    }


    
public void Remove(IBox box)
    
{
        
throw new Exception();
    }

}

這是對象類的定義,它僅僅實現過了Process方法,表明這個對象需要處理的工作。

public class ContainerBox : IBox
{
    ArrayList list 
= null;

    
public ContainerBox()
    
{
        list 
= new ArrayList();
    }


    
public void Add(IBox box)
    
{
        list.Add(box);
    }


    
public void Remove(IBox box)
    
{
        list.Remove(list);
    }


    
public void Process()
    
{
        
//1.Do Something for myself

        
//2.Do process for the box in the list
        foreach (IBox box in list)
        
{
            box.Process();
        }

    }

}

這是容器的實現代碼在Add和Remove方法中,我們可以添加實現了IBox接口的對象或容器,在Process方法中,我們依次調用IBox接口的Process方法將每個Box處理一次。

那麼我們在客戶程序可以像如下代碼一樣使用

static void Main(string[] args)
{
    IBox box 
= Factory.GetBox();

    box.Add(
new SingleBox());

    IBox box1 
= Factory.GetBox();

    box1.Add(box);

    box1.Process();
}

可以說我們在容器的Process方法裏實現了遞歸。

Composite模式的幾個要點:

  • Composite模式採用樹形結構來實現普遍存在的對象容器,從而將"一對多"的關係轉化爲"一對一"的關係,使得客戶代碼可以一致地處理對象和對象容器,無需關心處理的是單個的對象,還是組合的對象容器。
  • 將"客戶代碼與複雜的對象容器結構"解耦是Composite模式的核心思想,解耦之後,客戶代碼將與純粹的抽象接口--而非對象容器的復內部實現結構--發生依賴關係,從而更能"應對變化"。
  • Composite模式中,是將"Add和Remove等和對象容器相關的方法"定義在"表示抽象對象的Component類"中,還是將其定義在"表示對象容器的Composite類"中,是一個關乎"透明性"和"安全性"的兩難問題,需要仔細權衡。這裏有可能違背面向對象的"單一職責原則",但是對於這種特殊結構,這又是必須付出的代價。ASP.NET控件的實現在這
    方面爲我們提供了一個很好的示範。
  • Composite模式在具體實現中,可以讓父對象中的子對象反向追溯;如果父對象有頻繁的遍歷需求,可使用緩存技巧來改善效率。

Composite模式普遍用於控件中,如控件可以是容器,但是控件也可以被另外一個控件加入,那麼另外一個控件也是一個容器。在Asp.Net中也是如此。如果我們將IBox接口看作Control接口,Process方法改爲Render方法,就是繪製自己。那麼我們會發現,我們把控件慢慢的組合成樹,然後使用樹的根節點的Render方法,那麼我們就將控件容器下的控件和控件容器都Render出來了。

在Asp.Net中Control是使用ControlCollection來實現的,那麼它是通過在IBox接口裏添加一個Box屬性,返回值爲IBox,那麼我們對象實現這個接口的時候,get訪問器可以返回爲空。這就是Asp.Net控件給我們提供的很好的示範。如何來權衡透明性和安全性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章