Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1798335
  • 博文数量: 438
  • 博客积分: 9799
  • 博客等级: 中将
  • 技术积分: 6092
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-25 17:25
文章分类

全部博文(438)

文章存档

2019年(1)

2013年(8)

2012年(429)

分类: C/C++

2012-03-25 19:02:50

你的项目用了一个功能很强大的第三方库的类,你围绕着这个类写了很多代码。


  1. class OldClass
  2. {
  3. public:
  4.     void function1();
  5.     void function2();
  6.     void function3();
  7. }

  8. class Client
  9. {
  10.     void DoSomething()
  11.     {
  12.         OldClass* p = new OldClass;
  13.         p->function1();
  14.         p->funciton2();
  15.         p->function3();
  16.     }
  17. };

突然有一天,另一个库发布了一个更强大更高效更稳定但功能相同的类,可是里面的类的API与你现在用的API完全不同。
  1. class NewClass
  2. {
  3. public:
  4.     void function_one();
  5.     void function_two();
  6.     void function_three();
  7. };

出于性能考虑,你急需使用这个新类,可这样一来Client就要改大量的代码,怎么办?这时可以建一个适配器。
  1. class Adapter
  2. {
  3. public:
  4.     Adapter(NewClass* pNew) : mpNew(pNew) {}
  5.     void function1() { mpNew->function_one(); }
  6.     void function2() { mpNew->function_two(); }
  7.     void function3() { mpNew->function_three(); }
  8. private:
  9.     NewClass* mpNew;
  10. };

Client就可以修改少量代码:
  1. class Client
  2. {
  3.     void DoSomething()
  4.     {
  5.         Adapter* p = new Adapter(new NewClass);
  6.         p->function1();
  7.         p->function2();
  8.         p->function3();
  9.     }
  10. };

对象适配器类适配器
上面介绍的适配器就是对象适配器,它用的是组合的形式:
  1. interface ObjectAdapter
  2. {
  3.     void setAdaptee(Adaptee* p) = 0;
  4.     // all the APIs from the target class
  5.     void function() = 0;
  6. };

Adaptee就是上述的NewClass,target就是上述的OldClass。

另一种是类适配器,它用的是多重继承的形式,而非组合:


  1. class ClassAdapter : public Target, public Adaptee
  2. {
  3. };

比较两种适配器:

对象适配器——优点:使用组合,更灵活,可以支持Adaptee的所有子类。缺点:需要重新定义Target中的所有API。

类适配器——优点:高效,所需代码量少。缺点:不灵活,只支持Adaptee而不能支持其子类。

对象适配器的优点比较明显,下面展示下类适配器的优点:
  1. class Target
  2. {
  3. public:
  4.     virtual void function1();
  5.     virtual void function2();
  6.     virtual void function3();
  7. };

  8. class Adaptee
  9. {
  10. public:
  11.     virtual void function_two();
  12. };

注意到Adaptee中只有一个函数,如果用对象适配器,则除了转接function2之外,还要自己实现function1和function3。但如果是类适配器,只需要覆写function2就可以
  1. class ClassAdapter : public Target, public Adapee
  2. {
  3. public:
  4.     virtual void function2() { Adapee::function_two(); }
  5. };

下面探讨下外观模式
假如你是个将军,在打仗时布置了好几套方案。方案一:突击队先佯攻,接着敢死队强攻,然后爆破兵近距离布置炸药。方案二:首先爆破兵远程炮击,接着突击队两侧夹击,之后敢死队扫荡。方案三……
布置好方案后,你选择了其中一套方案,然后亲力亲为带领着突击队、敢死队和爆破兵冲锋陷阵。
可能会有两种不幸的结果:将军战死沙场,或者,将军被活活累死……

如果有个好的军师在你身边,帮你出谋划策。首先军师会制定出几套方案供你选择,你选择其中一套后,就交给军师去打理,军师会把你的命令传达下去,你只要坐在司令部静候佳音。

这个军师就是外观。


  1. class StaffOfficer
  2. {
  3. public:
  4.     void scheme_one() { SoldierA s1; SoldierB s2; s1.attack(); s2.blowUp(); }
  5.     void scheme_two() { SoldierC s1; SoldierD s2; s1.bombard(); s2.outflank(); }
  6. };

  7. class General
  8. {
  9.     void DoSomething()
  10.     {
  11.         StaffOfficer *officer = new StaffOfficer;
  12.         officer->scheme_one();
  13.     }
  14. };

其中SoldierA、B、C、D都属于子系统的类,如果没有外观,client就需要和子系统内部的类高度耦合,这样子系统内部就不容易改变。加入外观后,client就只需要和外观打交道,而不需要知道子系统内部的细节。

外观模式提供了一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层接口,让子系统更容易使用。

设计原则:只和你的密友交谈。(最少知识原则)

外观与适配器的区别:

外观的作用是简化接口,让客户与子系统的类解耦。

适配器的作用是将接口转换成不同接口。

阅读(827) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~