在某些情況下,客戶代碼過多地依賴於對象容器複雜的內部實現結構,對象容器內部實現結構(而非抽象介面)的變化將引起客戶代碼的頻繁變化,帶來了代碼的維護性、擴充性等弊端。
如何將“客戶代碼與複雜的對象容器結構”解耦?讓對象容器自己來實現自身的複雜結構,從而使得客戶代碼就像處理簡單對象一樣來處理複雜的對象容器?
意圖:
將對象組合成樹形結構以表示“部分-整體”的階層。Composite使得使用者對單個對象和組合對象的使用具有一致性。
public interface IBox
{
void Process();
void Add(IBox box);
void Remove(IBox box);
}
public class SingleBox : IBox
{
public void Process()
{
//1、Do process for myself
}
public void Add(IBox box)
{
throw UnsuporttedException();
}
public void Remove(IBox box)
{
throw UnsuporttedException();
}
}
public class ContainerBox : IBox
{
ArrayList list = null;
public void Add(IBox box)
{
if (list == null)
{
list = new ArrayList();
}
list.Add(box);
}
public void Remove(IBox box)
{
if (list == null)
{
throw new Exception();
}
list.Remove(box);
}
public void Process()
{
if (list != null)
{
//1、Do process for myself
//2、Do process for the box in the list
foreach (IBox box in list)
{
box.Process();
}
}
}
}
//客戶代碼
class App
{
IBox box = Factory.GetBox();
box.Process();
}
要點:
1、Composite模式採用樹形結構來實現普遍存在的對象容器,從而將“一對多”的關係轉化為“一對一”的關係,使得客戶代碼可以一致地處理對象和對象容器,無需關心處理的是單個的對象,還是組合的對象容器;
2、將“客戶代碼與複雜的對象容器結構”解耦是Composite模式的核心思想,解耦之後,客戶代碼將與純粹的抽象介面——而非對象容器的複內部實現結構——發生依賴關係,從而更能“應對變化”。
3、Composite模式中,是將“Add和Remove等和對象容器相關的方法”定義在“表示抽象對象的Component類”中,還是將其定義在“表示對象容器的Composite類”中,是一個關乎“透明性”和“安全性”的兩難問題,需要仔細權衡。這裡有可能違背物件導向的“單一職責原則”,但是對於這種特殊結構,這又是必須付出的代價。ASP.NET控制項的實現在這方面為我們提供了一個很好的示範。
4、Composite模式在具體實現中,可以讓父物件中的子物件反向追溯;如果父物件有頻繁的遍曆需求,可使用緩衝技巧來改善效率。