C++ Decorator Design Mode

概要

又是一种比较常见也比较常用的模式。系统模块经常需要进行功能上的扩展,比如下面这种形式的结构,
当需要扩展新Function时,通常会通过继承追加新类来实现功能的扩展。但是如果我们不是扩展一个新功能的对象,而只是对所有现有的每种功能类的处理进行扩展时,我们应该怎么做?Decorator模式可以很好的解决这类问题。

目的
为一系列对象动态追加(或删除)额外的功能,并保证统一的外部接口

实例
考虑这样一个比较典型的例子吧。UI中会用到很多种的window,比如对话框,菜单,tab窗口,树状窗口等。

  1. class BaseWin {  
  2. public:  
  3.      virtual void Show();  
  4. };  
  5. class TabWin : public BaseWin {  
  6. public:  
  7.      virtual void Show();  
  8. };  
  9. class TreeWin : public BaseWin {  
  10. public:  
  11.      virtual void Show();  
  12. };  
  13. ......  
class BaseWin {
public:
     virtual void Show();
};
class TabWin : public BaseWin {
public:
     virtual void Show();
};
class TreeWin : public BaseWin {
public:
     virtual void Show();
};
......

如果有需求需要追加这样的功能:为每种window控件都追加在window框中显示某个logo的功能,怎么解决?
最笨的方法:每种window都加这种功能,通过isShowlogo变量来决定是否显示logo,
  1. class BaseWin {  
  2. public:  
  3.      virtual void Show();  
  4.      virtual void DisplayLogo();  
  5. protected:  
  6.      BOOL     mIsShowLogo;  
  7. };  
  8. class TabWin : public BaseWin {  
  9. public:  
  10.      virtual void Show() {  
  11.           if (mIsShowLogo) {  
  12.                DisplayLogo();  
  13.           }                 
  14.           ......  
  15.      }  
  16. };  
  17. class TreeWin : public BaseWin {  
  18. public:  
  19.      virtual void Show() {  
  20.           if (mIsShowLogo) {  
  21.                DisplayLogo();  
  22.           }   
  23.           ......  
  24.      }  
  25. };  
  26. ......  
class BaseWin {
public:
     virtual void Show();
     virtual void DisplayLogo();
protected:
     BOOL     mIsShowLogo;
};
class TabWin : public BaseWin {
public:
     virtual void Show() {
          if (mIsShowLogo) {
               DisplayLogo();
          }               
          ......
     }
};
class TreeWin : public BaseWin {
public:
     virtual void Show() {
          if (mIsShowLogo) {
               DisplayLogo();
          } 
          ......
     }
};
......

每种window都要改,太麻烦了,我想每个开发者都不会愿意这样去扩展。也许有人会说,上面的方法还可以稍微改善一下,比如说把显示logo的处理都放在基类来进行:
  1. class BaseWin {  
  2. public:  
  3.      virtual void Show() {  
  4.           if (mIsShowLogo) {  
  5.                DisplayLogo();  
  6.           }  
  7.           WinShow();  
  8.      }  
  9.      virtual void WinShow();  
  10.      virtual void DisplayLogo();  
  11. protected:  
  12.      BOOL     mIsShowLogo;  
  13. };  
  14. class TabWin : public BaseWin {  
  15. public:  
  16.      virtual void WinShow();  
  17. };  
  18. class TreeWin : public BaseWin {  
  19. public:  
  20.      virtual void WinShow() ;  
  21. };  
  22. ......  
class BaseWin {
public:
     virtual void Show() {
          if (mIsShowLogo) {
               DisplayLogo();
          }
          WinShow();
     }
     virtual void WinShow();
     virtual void DisplayLogo();
protected:
     BOOL     mIsShowLogo;
};
class TabWin : public BaseWin {
public:
     virtual void WinShow();
};
class TreeWin : public BaseWin {
public:
     virtual void WinShow() ;
};
......

但是首先这样会涉及到对基类和子类调用方式的调整,其次把logo显示的处理跟原来的处理耦合在一起会带来额外的风险,同时如果又需要对这些window再统一添加其他功能时又会涉及到再次的复杂的改动,扩展性比较差。
那么让我们进入正题,还是看看Decorator模式怎么解决的。

  1. class BaseWin {  
  2. public:  
  3.      virtual void Show();  
  4. };  
  5. class TabWin : public BaseWin {  
  6. public:  
  7.      virtual void Show();  
  8. };  
  9. class TreeWin : public BaseWin {  
  10. public:  
  11.      virtual void Show();  
  12. };  
  13. ......  
  14. class DecoratorWin: public BaseWin {  
  15. public:  
  16.      DecoratorWin(BaseWin* win) {  
  17.           mWin = win;  
  18.      }  
  19.      virtual void Show() {  
  20.           mWin->Show();  
  21.      }  
  22. private:  
  23.      BaseWin* mWin;  
  24. };  
  25. class LogWin: public DecoratorWin {  
  26. public:  
  27.     LogWin(BaseWin* win) : Decorator(win){  
  28.      }  
  29.      void DisplayLogo();  
  30.      virtual void Show() {  
  31.           DisplayLogo();  
  32.           DecoratorWin::Show();  
  33.      }  
  34. };  
class BaseWin {
public:
     virtual void Show();
};
class TabWin : public BaseWin {
public:
     virtual void Show();
};
class TreeWin : public BaseWin {
public:
     virtual void Show();
};
......
class DecoratorWin: public BaseWin {
public:
     DecoratorWin(BaseWin* win) {
          mWin = win;
     }
     virtual void Show() {
          mWin->Show();
     }
private:
     BaseWin* mWin;
};
class LogWin: public DecoratorWin {
public:
    LogWin(BaseWin* win) : Decorator(win){
     }
     void DisplayLogo();
     virtual void Show() {
          DisplayLogo();
          DecoratorWin::Show();
     }
};

从BaseWin类继承添加DecoratorWin类,它包含一个指向BaseWin对象的指针,它的Show方法调用mWin指向的BaseWin对象的Show方法。具体扩展时再从DecoratorWin类继承来实现,比如LogWin类实现了显示Logo的方法,并在Show方法中调用显示Logo方法。当然对接口使用Client端来说是不用关心内部处理的,因为它们都具有统一的外部接口。如下所示是Client端调用带有Logo显示的TabWin的处理。
  1. BaseWin* tab = new TabWin();  
  2. BaseWin* logo = new LogWin(tab);  
  3. logo->Show();  
BaseWin* tab = new TabWin();
BaseWin* logo = new LogWin(tab);
logo->Show();

这样的扩展有什么好处呢?第一,改动范围小,而且不需要调整原有的代码,变更风险小;第二,可扩展性强,模块灵活性强;第三;扩展类具有跟原来一致的外部接口。

应用
Decorator除了可以追加功能外,也可以统一去剥离现有的部分功能。当然由于Decorator模式是在运行时动态的改变对象职责,所以也会给调试增加一定难度。从目前已知应用来看,使用时相当广泛的,比如对一些IOStream的封装和扩展,而在GUI工具库中Decorator模式的使用的是最多的。另外,也要区分清楚Adapter模式和Decorator模式的区别,Adapter模式改变的是对象的接口,而Decorator改变的是对象的功能。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值