设计模式之适配器模式
「适配器模式」将一个类的接口转换成客户希望的另外一个接口,使得原本不兼容的接口一起工作。
意义
在于将某些功能与第三方需求接口适配对接,且避免第三方接口与功能代码过多耦合。
在设计初初,不要考虑使用此模式。仅在功能完善,需要实现第三方接口时,没必要迎合第三方的需求对原来的设计大动刀戈,可以尝试使用适配器模式。
多用于想应用某些功能,但是功能类的接口与需求的接口不兼容时,采用适配器模式来解决。主要应用在以下场景:
- 新旧接口兼容软件版本升级,部分旧接口还在被使用。需要保留旧的接口,增加新接口,使两者兼容。
- 第三方接口的适配在系统功能稳定的情况下,有第三方新的接口需求需要对接。
- 统一多个类相同功能的接口例如统一不同类型数据库的访问接口。
两种模式适配器介绍
适配器模式有两种类别:类模式和对象模式,即我们面对对象中常见的继承(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;
}