适配器模式是软件开发中常用的模式之一,比如我们之前写的类提供的接口(老的接口)在新的环境下已经不合适了,那么我们怎么改变才能使老的接口适配现在新的接口呢?之前说过设计模式中常用的手法就是组合和继承,这在适配器模式中得到了很好的体现。首先,我们要从新的接口继承一个类,这个类就是适配器类(为什么要从新接口继承?那是为了遵循新接口提供的接口规范),那这个适配器类要怎么去适配老的接口呢?很显然的办法是用组合,包含一个指向被适配类的引用,
适配器模式的定义:将一个类的接口转换成客户希望的另外一个接口,从而使原本由于接口不兼容而不能一起工作的类可以一起工作。
用现实中的列子来类比,比如我们常见的电源适配器,就是将原来的接口(不合适的电压),转换成现在可用的接口(
UML类图
上图是适配器模式的第一种实现形式,适配器Adapter继承自Target和Adaptee类,Adapter类需要重写Target类的Request函数,在Request中做适当的处理,调用Adaptee类的SepcificRequest。最终,Target实际调用的是Adaptee的SpecificRequest来完成Request的,完成适配;这种叫做类适配器。
上图是适配器的第二种实现形式,适配器Adapter类继承自Target类,同时,在Adapter类中有一个Adaptee类型的成员变量;Adapter类重写Request函数时,在Request中,使用Adaptee类型的成员变量调用Adaptee的SpecificRequest函数,最终完成适配;这种叫做对象适配器。
类适配器和对象适配器的比较
既然有了类适配器和对象适配器,那么在实际中如何在二者之间做选择呢?
类适配器有以下特点:
1.由于Adapter直接继承自Adaptee类,所以,在Adapter类中可以对Adaptee类的方法进行重定义;
2.如果在Adaptee中添加了一个抽象方法,那么Adapter也要进行相应的改动,这样就带来高耦合;
3.如果Adaptee还有其它子类,而在Adapter中想调用Adaptee其它子类的方法时,使用类适配器是无法做到的。
对象适配器有以下特点:
1.有的时候,你会发现,不是很容易去构造一个Adaptee类型的对象;
2.当Adaptee中添加新的抽象方法时,Adapter类不需要做任何调整,也能正确的进行动作;
3.可以使用多肽的方式在Adapter类中调用Adaptee类子类的方法。
由于对象适配器的耦合度比较低,所以在很多的书中都建议使用对象适配器。在我们实际项目中,也是如此,能使用对象组合的方式,就不使用多继承的方式。
代码实现
类适配器的实现代码
复制代码代码如下:
/*
** FileName : AdapterPatternDemo
** Author : Jelly Young
** Date : 2013/11/27
** Description : More information, please go to http://www.jellythink.com
*/
#include
using namespace std;
// Targets
class Target
{
public:
virtual void Request()
{
cout<<“Target::Request”<<endl;
}
};
// Adaptee
class Adaptee
{
public:
void SpecificRequest()
{
cout<<“Adaptee::SpecificRequest”<<endl;
}
};
// Adapter
class Adapter : public Target, Adaptee
{
public:
void Request()
{
Adaptee::SpecificRequest();
}
};
// Client
int main(int argc, char *argv[])
{
Target *targetObj = new Adapter();
targetObj->Request();
delete targetObj;
targetObj = NULL;
return 0;
}
对象适配器的代码实现
复制代码代码如下:
/*
** FileName : AdapterPatternDemo
** Author : Jelly Young
** Date : 2013/11/27
** Description : More information, please go to http://www.jellythink.com
*/
#include
using namespace std;
class Target
{
public:
Target(){}
virtual ~Target(){}
virtual void Request()
{
cout<<“Target::Request”<<endl;
}
};
class Adaptee
{
public:
void SpecificRequest()
{
cout<<“Adaptee::SpecificRequest”<<endl;
}
};
class Adapter : public Target
{
public:
Adapter() : m_Adaptee(new Adaptee) {}
~Adapter()
{
if (m_Adaptee != NULL)
{
delete m_Adaptee;
m_Adaptee = NULL;
}
}
void Request()
{
m_Adaptee->SpecificRequest();
}
private:
Adaptee *m_Adaptee;
};
int main(int argc, char *argv[])
{
Target *targetObj = new Adapter();
targetObj->Request();
delete targetObj;
targetObj = NULL;
return 0;
}
总结 
结合到我们的例子和适配器模式的定义,其中稳定的部分就是目标接口类和源接口类,而变化的是适配器类,因为如果有新的目标接口的话适配器类就做出相应的改变,以适应新的接口。我们通过继承的方式来得到新接口的接口规范(就是要用它的虚函数),然后通过组合的方式(就是包含一个老接口的指针作为适配器类的成员)得到老接口的某些使用方法从而达到适应新接口的目的。