适配器模式的定义:适配器模式将一个类的接口转换成客户期望的另一个接口,让原本不兼容的接口可以合作无间。
该模式应该好理解。比如电源适配器(中国和欧洲分别是电源220V,110V)就是该模式的一种表现。关于类图或者其他说明我这边就不啰嗦了。很多开发者包括我自己也是,更多困惑是不知道在实际的项目中该如何使用设计模式。本文希望通过例子来说明什么情况下使用适配器模式,算是抛砖引玉吧。
使用场景:我们准备开发一个新模块或者功能。现在的情况是我们已经有现成可用的模块或者第三方库,这些模块经过客户测试是完全符合需求的,而且是稳定的。当然大家都希望直接调用这些模块,而不是费时费力的从头开发。问题是通过分析现有模块的接口或者第三方库的时候,发现直接调用比较麻烦或者不符合现在的编程模式。比如数据结构的定义不一致,比如返回值不一致,比如接口参数不一致(很多时候第三方库考虑各种兼容性,而我们其实不一定需要)。
怎么办呢?好办,增加一个"中间层"解决。这个中间层就是"适配器模式"。如果不增加这个"中间层",或多或少会打乱我们现有的接口定义或者编码方式。
实现方式:一般是通过类适配器或者是通过对象适配器。如何区分这2种呢?类适配器是通过"多继承",即继承的方式实现,耦合性很高,父类变化了子类就需要重新编译链接,而且"多继承"容易产生二义性,不建议使用。对象适配器是通过对象组合"的方式实现,耦合性低,通常使用该方式。符合面向对象设计的一个基本原则"优先使用组合,而不是继承"。
OK,最后还是通过例子来说明吧:
该模式应该好理解。比如电源适配器(中国和欧洲分别是电源220V,110V)就是该模式的一种表现。关于类图或者其他说明我这边就不啰嗦了。很多开发者包括我自己也是,更多困惑是不知道在实际的项目中该如何使用设计模式。本文希望通过例子来说明什么情况下使用适配器模式,算是抛砖引玉吧。
使用场景:我们准备开发一个新模块或者功能。现在的情况是我们已经有现成可用的模块或者第三方库,这些模块经过客户测试是完全符合需求的,而且是稳定的。当然大家都希望直接调用这些模块,而不是费时费力的从头开发。问题是通过分析现有模块的接口或者第三方库的时候,发现直接调用比较麻烦或者不符合现在的编程模式。比如数据结构的定义不一致,比如返回值不一致,比如接口参数不一致(很多时候第三方库考虑各种兼容性,而我们其实不一定需要)。
怎么办呢?好办,增加一个"中间层"解决。这个中间层就是"适配器模式"。如果不增加这个"中间层",或多或少会打乱我们现有的接口定义或者编码方式。
实现方式:一般是通过类适配器或者是通过对象适配器。如何区分这2种呢?类适配器是通过"多继承",即继承的方式实现,耦合性很高,父类变化了子类就需要重新编译链接,而且"多继承"容易产生二义性,不建议使用。对象适配器是通过对象组合"的方式实现,耦合性低,通常使用该方式。符合面向对象设计的一个基本原则"优先使用组合,而不是继承"。
OK,最后还是通过例子来说明吧:
/* 被适配者,Adaptee */
class API3rd
{
public:
int fun1(int param1,int param2,float f1,float f2)
{
printf("API3rd::fun1\r\n");
return 1;
}
float fun2()
{
printf("API3rd::fun2\r\n");
return 0.1;
}
};
/* Target类 */
class MyClass
{
public:
MyClass(){};
virtual ~MyClass(){}
virtual int f1(int param1)
{
printf("MyClass::f1\r\n");
return 0;
}
virtual int f2()
{
printf("MyClass::f2\r\n");
return 0;
}
};
/* 类适配器,使用多继承 */
class Adapter1 : private API3rd,private MyClass
{
public:
virtual int f1(int param1)
{
printf("Adapter1::f1\r\n");
printf("由于API提供的接口参数太多,我们只需要关注一个参数即可。因此使用适配器模式对该接口适配。\r\n");
return API3rd::fun1(param1,0,0.0,0.0);
}
virtual int f2()
{
printf("Adapter1::f2\r\n");
printf("由于API提供的接口的返回值不符合我们的需要,因此使用适配器模式对该接口进行适配\r\n");
float f = API3rd::fun2();
return (f+0.5);
}
};
/* 对象适配器,使用对象组合的方式代替继承 */
class Adapter2 : private MyClass
{
public:
Adapter2()
{
m_api = new API3rd();
}
~Adapter2()
{
if(m_api)
{
delete m_api;
}
}
virtual int f1(int param1)
{
printf("Adapter2::f1\r\n");
printf("由于API提供的接口参数太多,我们只需要关注一个参数即可。因此使用适配器模式对该接口适配。\r\n");
return m_api->fun1(param1,0,0.0,0.0);
}
virtual int f2()
{
printf("Adapter2::f2\r\n");
printf("由于API提供的接口的返回值不符合我们的需要,因此使用适配器模式对该接口进行适配\r\n");
float f = m_api->fun2();
return (f+0.5);
}
private:
API3rd* m_api;
};
/* Client 调用场景 */
void TestAdapter()
{
Adapter1* ap1 = new Adapter1;
ap1->f1(2);
ap1->f2();
Adapter2* ap2 = new Adapter2;
ap2->f1(2);
ap2->f2();
delete ap1;
delete ap2;
}