C++实现设计模式——适配器(Adapter)模式
- 适配器模式定义
Adapter(适配器模式)属于结构型模式,结构性模式关注的是如何组合类与对象,以获得更大的结构,我们平常工作大部分时间都在与这种设计模式打交道。
意图:将一个类的接口转换成客户希望的另一个接口。Adapter 模式使得原本由于接口不兼容而不能在一起工作的那些类可以一起工作。
-
适配器应用场景
- 新旧 API 兼容。(大型使用库的升级)
- 三方包适配。
- 统一多个类的接口。(比如数据库ORM)
- 两种模式适配器介绍
适配器模式有两种类别:类模式和对象模式,即我们面对对象中常见的继承(is A)与组合(has A),两者的目的都是功能的复用,那么如何选择呢?
首先看第一个例子:
数据库的ORM,go语言相信大家都知道吧,它可以支持用同一个接口对mysql,sqlite3,postgersql三种数据库进行访问,只要在开始的时候进行一下驱动注册。像这种情况我们就可以用继承的适配方式来实现,对于orm来说mysql,sqlite3,postgersql结构很类似只要屏蔽一下少量的平台差异就可以做到。
这种情况的结构图为:
代码示例:
#include <iostream>
using namespace std;
enum sqlType {
mysqlType = 1,
sqlite3Type,
postgersqlType
};
enum sqlType type;
class mysql {
public:
void select() {
cout<<"mysql select"<<endl;
}
};
class sqlite3 {
public:
void select() {
cout<<"sqlite3 select"<<endl;
}
};
class postgersql {
public:
void select() {
cout<<"postgersql select"<<endl;
}
};
class ORM:public mysql,public sqlite3,public postgersql {
public:
void orm_select() {
switch(type) {
case mysqlType:
mysql::select();
break;
case sqlite3Type:
sqlite3::select();
break;
case postgersqlType:
postgersql::select();
break;
default:
break;
}
}
};
void init_sqltype(enum sqlType t){ //注册驱动是哪个类型
type = t;
}
int main() {
ORM *o = new ORM();
init_sqltype(mysqlType);
o->orm_select();
init_sqltype(sqlite3Type);
o->orm_select();
init_sqltype(postgersqlType);
o->orm_select();
delete o;
return 0;
}
第二个例子:
假如现在要对C++的STL库进行含有 break change 的升级时,比如减少了参数,一些旧的API就需要标记为废弃的,但也不能说废弃就废弃,还需要留些时间给用户来进行升级,此时我们就可以用组合适配器的方式来解决这个问题,首先继承old API,同时再包含new API特性,用户就可以通过适配器,即能使用原有的老的接口,还能使用新特性。
这种情况的结构图:
代码例子:
#include <iostream>
using namespace std;
class API { //旧的API
public:
void old_apply() {
cout<<"old api"<<endl;
}
};
class new_API { //新的API
public:
void new_apply() {
cout<<"new api"<<endl;
}
};
class dep_API :public API{ //标记为要废弃的API
public:
new_API *_api;
dep_API() {
_api = new new_API();
}
void new_apply() {
_api->new_apply();
}
};
void apply(int a,int b,int c) {
//API a1; 原先的老的接口函数
//a1.old_apply();
dep_API a1;
a1.new_apply();
}
void apply(int a,int b) {
new_API a1;
a1.new_apply();
}
int main() {
apply(1,2,3);
apply(1,2);
return 0;
}
如代码中所示的API库升级后,apply参数由多变少,同时将原来 old_apply接口都全局替换变成了new_apply,如果继续使用老的接口肯定就报错,用了适配器兼容后就解决了问题。
综上:当统一多个类的接口,且每个类的结构很类似的时候使用继承适配器模式,当是要兼容旧接口,添加新特性的这种场合可以用组合适配器模式。