你的项目用了一个功能很强大的第三方库的类,你围绕着这个类写了很多代码。
- class OldClass
- {
- public:
- void function1();
- void function2();
- void function3();
- }
- class Client
- {
- void DoSomething()
- {
- OldClass* p = new OldClass;
- p->function1();
- p->funciton2();
- p->function3();
- }
- };
突然有一天,另一个库发布了一个更强大更高效更稳定但功能相同的类,可是里面的类的API与你现在用的API完全不同。
- class NewClass
- {
- public:
- void function_one();
- void function_two();
- void function_three();
- };
出于性能考虑,你急需使用这个新类,可这样一来Client就要改大量的代码,怎么办?这时可以建一个适配器。
- class Adapter
- {
- public:
- Adapter(NewClass* pNew) : mpNew(pNew) {}
- void function1() { mpNew->function_one(); }
- void function2() { mpNew->function_two(); }
- void function3() { mpNew->function_three(); }
- private:
- NewClass* mpNew;
- };
Client就可以修改少量代码:
- class Client
- {
- void DoSomething()
- {
- Adapter* p = new Adapter(new NewClass);
- p->function1();
- p->function2();
- p->function3();
- }
- };
对象适配器与
类适配器
上面介绍的适配器就是对象适配器,它用的是组合的形式:
- interface ObjectAdapter
- {
- void setAdaptee(Adaptee* p) = 0;
- // all the APIs from the target class
- void function() = 0;
- };
Adaptee就是上述的NewClass,target就是上述的OldClass。
另一种是类适配器,它用的是多重继承的形式,而非组合:
- class ClassAdapter : public Target, public Adaptee
- {
- };
比较两种适配器:
对象适配器——优点:使用组合,更灵活,可以支持Adaptee的所有子类。缺点:需要重新定义Target中的所有API。
类适配器——优点:高效,所需代码量少。缺点:不灵活,只支持Adaptee而不能支持其子类。
对象适配器的优点比较明显,下面展示下类适配器的优点:
- class Target
- {
- public:
- virtual void function1();
- virtual void function2();
- virtual void function3();
- };
- class Adaptee
- {
- public:
- virtual void function_two();
- };
注意到Adaptee中只有一个函数,如果用对象适配器,则除了转接function2之外,还要自己实现function1和function3。但如果是类适配器,只需要覆写function2就可以
- class ClassAdapter : public Target, public Adapee
- {
- public:
- virtual void function2() { Adapee::function_two(); }
- };
下面探讨下
外观模式。
假如你是个将军,在打仗时布置了好几套方案。方案一:突击队先佯攻,接着敢死队强攻,然后爆破兵近距离布置炸药。方案二:首先爆破兵远程炮击,接着突击队两侧夹击,之后敢死队扫荡。方案三……
布置好方案后,你选择了其中一套方案,然后亲力亲为带领着突击队、敢死队和爆破兵冲锋陷阵。
可能会有两种不幸的结果:将军战死沙场,或者,将军被活活累死……
如果有个好的军师在你身边,帮你出谋划策。首先军师会制定出几套方案供你选择,你选择其中一套后,就交给军师去打理,军师会把你的命令传达下去,你只要坐在司令部静候佳音。
这个军师就是外观。
- class StaffOfficer
- {
- public:
- void scheme_one() { SoldierA s1; SoldierB s2; s1.attack(); s2.blowUp(); }
- void scheme_two() { SoldierC s1; SoldierD s2; s1.bombard(); s2.outflank(); }
- };
- class General
- {
- void DoSomething()
- {
- StaffOfficer *officer = new StaffOfficer;
- officer->scheme_one();
- }
- };
其中SoldierA、B、C、D都属于子系统的类,如果没有外观,client就需要和子系统内部的类高度耦合,这样子系统内部就不容易改变。加入外观后,client就只需要和外观打交道,而不需要知道子系统内部的细节。
外观模式提供了一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层接口,让子系统更容易使用。
设计原则:只和你的密友交谈。(最少知识原则)
外观与适配器的区别:
外观的作用是简化接口,让客户与子系统的类解耦。
适配器的作用是将接口转换成不同接口。
阅读(825) | 评论(0) | 转发(0) |