1. 程式人生 > >【設計模式攻略】結構型模式之Composite模式

【設計模式攻略】結構型模式之Composite模式

概要 具備一系列既有獨立功能,又需要排列組合其中的幾種功能來達成一些複合的新功能時,可以採用組合模式。比如說,你設計了一個備份模組,有email備份,note備份,message備份,log備份等一系列備份功能,而你又會需要同時備份它們中間不定的幾種時,考慮用組合模式吧。它能組合物件處理,而又不增加額外的耦合,並保證介面一致,以及模組的易用性和擴充套件性。 目的 自由組合既有物件處理來實現複合物件,保證單一物件和複合物件具有統一的對外介面。 例項 Command模式應該都比較熟悉了,這裡結合Command模式來舉個例子。 有時我們會把行為(action)封裝為類,比如我們需要如下這些action,儲存action,備份action,傳送action,顯示action等,那麼考慮用Command模式來進行封裝,如下所示:

class CommandAction {
public:
     virtual void Execute ();
};
class SaveAction : public CommandAction {
public:
     virtual void Execute ();
};
class BackupAction : public CommandAction {
public:
     virtual void Execute ();
};
class SendAction : public CommandAction {
public:
     virtual void Execute ();
};
......

我們有需要實現幾種複合行為,Composite1是(儲存+備份)action,Composite2是(儲存+顯示)action,Composite3是(儲存+顯示+傳送)action,不要告訴我你會如下這樣去實現!為每種複合行為都設計一個類?
class CommandAction {
public:
     virtual void Execute ();
};
class Composite1: public CommandAction {
public:
     ......
     virtual void Execute () {
          mSave->Execute();
          mBackup->Execute();          
     }
private:
     SaveAction* mSave;
     BackupAction * mBackup;     
};

(省略Composite2, Composite3) 很容易看出,這不是一種好方法,擴充套件性太差,增加了類間的耦合度。如果又需要更多的不同的複合行為,難道再繼續追加類?太複雜,太煩了,模組維護者看到這種設計會瘋掉的。 那麼,讓我們看看如果用Composite模式是怎麼解決的。
class CommandAction {
public:
     virtual void Execute() = 0;
     virtual void AddAction(CommandAction* action);
     virtual void DeleteAction(CommandAction* action);
};
class CompositeAction : public CommandAction {
public:
     ......
     virtual void Execute() {
          list<CommandAction*>::iterator it;
          for (it = mCompositor.begin(); it != mCompositor.end(); it++) {
               if (*it != NULL) {
                    (*it)->Execute(pack);
               }
          }
     }
     virtual void AddAction(CommandAction* action) {
          if (action != NULL) {
               mCompositor.push_back(action);
          }
     }
     virtual void DeleteAction(CommandAction* action) {
          list<CommandAction*>::iterator it;
          if (action != NULL) {
               for (it = mCompositor.begin(); it != mCompositor.end(); it++) {
               if (*it == action) {
               mCompositor.erase(it);
               break;
               }
          }
     }
private:
     list<CommandAction*> mCompositor;
};

設計一個CompositeAction類,具有跟其他Action統一的介面(Execute),CompositeAction包含一個基類CommandAction的list容器物件,通過AddAction和DeleteAction,可以由Client呼叫方自由追加和刪除複合物件中需要包含的Action,而Execute方法會執行list中push進來的所有Action。 應用 在檔案系統庫中,儲存檔案節點包含資料夾和檔案的組合,而一些UI庫中,複雜的UI也經常會由很多可定製的基本UI組成,當然相關應用還有很多,在這些庫中,Composite模式經常會被使用。另外Composite模式也經常跟Decorator模式結合起來使用,關於Decorator模式,在下一單元會有詳細的說明。