设计模式---接口隔离模式之适配器模式(Adapter)
一:概念
通过Adapter模式可以改变已有类(或外部类)的接口形式
二:动机
在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的。
如何应对这种“迁移的变化”?如何既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?
生活中如电源适配器,vga转换线等,适配器模式可以通过将旧的类接口转化为新接口,从而解决新环境要求的接口问题。
三:模式定义
将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
--《设计模式》Gof
四:类图(结构)
五:代码讲解
//目标接口(新接口) class ITarget{ public: virtual void process()=0; }; //遗留接口(老接口) class IAdaptee{ public: virtual void foo(int data)=0; virtual int bar()=0; }; //遗留类型,符合老的接口 class OldClass: public IAdaptee{ //.... }; //对象适配器 class Adapter: public ITarget{ //继承 protected: IAdaptee* pAdaptee;//组合 public: Adapter(IAdaptee* pAdaptee){ this->pAdaptee=pAdaptee; } virtual void process(){ int data=pAdaptee->bar(); pAdaptee->foo(data); } };
int main(){ IAdaptee* pAdaptee=new OldClass(); ITarget* pTarget=new Adapter(pAdaptee); pTarget->process(); }
接口转换,将目标接口转目的接口,不一定是旧的旧和新,例如栈和队列转换,本身即是接口又是实现。
class stack{ //没有组合,没有指针,即是接口又是实现 deqeue container; }; class queue{ deqeue container; };
六:要点总结
(一)Adapter模式主要应用于“希望复用一些现存的类,但是接口又与服用环境要求不一致的情况”,在遗留代码复用、类库迁移等方面非常有用。
(二)GoF23定义了两种Adapter模式的结构实现:对象适配器和类适配器。但类适配器采用“多继承”的实现方式,一般不推荐使用。对象适配器采用“对象组合”的方式,更符合松耦合的精神。
1.对象适配器
//对象适配器 class Adapter: public ITarget{ //继承 protected: IAdaptee* pAdaptee;//组合,灵活性高 public: Adapter(IAdaptee* pAdaptee){ this->pAdaptee=pAdaptee; } virtual void process(){ int data=pAdaptee->bar(); pAdaptee->foo(data); } };
一个继承一个组合,就叫做对象适配器:因为他是通过组合对象来实现适配的
2.类适配器(不太好,用的很少,坏处更多)
//类适配器 class Adapter: public ITarget, protected OldClass{ //多继承,定死了,灵活性不高 }
通过多继承来实现类适配器,public继承是共有接口,我符合你的接口规范,protected和private继承是实现继承,并没有继承你的接口,但是我用你的实现
(三)Adapter模式可以实现的非常灵活,不必拘泥于GoF23中定义的两种结构。例如,完全可以将Adapter模式中的“现存对象”作为新的接口方法参数,来达到适配的目的。
七:案例实现:电压转换18-220v
class Current18V { public: virtual void use18vCurrent() { cout << "use 18v voltage" << endl; } }; class Current220V { public: void use220vCurrent() { cout << "use 220v voltage" << endl; } };
//继承接口规范,组合数据 class Adapter :public Current18V { private: Current220V* cur; public: Adapter(Current220V* c) :cur(c) { } virtual void use18vCurrent() { cout << "adapter use voltage" << endl; cur->use220vCurrent(); } };
void main() { Current220V* c2 = new Current220V(); Adapter* adapter = new Adapter(c2); adapter->use18vCurrent(); delete c2; delete adapter; system("pause"); return; }