[设计模式]结构模式-适配模式(C++描述)
second60 20180429
1. 什么是适配模式
在现有接口中,不修改原有接口的情况下,增加适配器,支持客户的需求。
适配器分为:类适配器模式和对象适配器模式。
现实生活中最简单的例子:手机能电器,我们家用电压为220V(Adaptee),但我们的手机只需12V的电压(Target)来充电。所以中间需要一个电压适配器(Adapter)来转换电压。
概念:
接口继承:通过继承子类获得了父类的接口(子类实现父类接口)
实现继承:通过继承子类获得父类的实现(子类调用父类接口)
在C++中
public继承:即是接口继承,也是实现继承(能重载父类的接口,又获得父类的接口实现)。
private继承:父类中的接口都变为private,只能是实现继承。
纯抽象基类:可以模似接口继承。
2. 适配器模式结构图
类适配模式
对象适配模式
区别:
类适配模式的Adapter采用继承的方式实现Adaptee的接口。
对象模式的Adapter中采用组合的方式实现Adaptee接口。
分析:
1. Target为面向用户的接口
2. Adaptee为原有功能接口
3. Adapter为适配器,在原有的接口上适配新功能
3 代码实现
3.1对象适配模式
// 目标接口
class Target
{
public:
virtual ~Target(){}
virtual void Request(){cout << “Target::Request” << endl;}
};
// 原有接口
class Adaptee
{
public:
Adaptee(){}
~Adaptee(){}
void SpecificRequest(){cout << “ Adaptee::SpecificRequest” << endl;}
};
//适配器
class Adapter:public Target
{
public:
Adapter(Adaptee *adaptee){_adaptee = adaptee;}
~Adapter(){}
void Request()
{
// do before....
_adaptee ->SpecificRequest();
// do after...
}
private:
Adaptee * _adaptee;
};
//使用
int main(int argc, char** argv)
{
Adaptee *adaptee = new Adaptee();
Target* target = new Adapter(adaptee);
target->Request();
return 0;
}
3.2 类适配模式
// 目标接口
class Target
{
public:
virtual ~Target(){}
virtual void Request(){cout << “Target::Request” << endl;}
};
// 原有接口
class Adaptee
{
public:
Adaptee(){}
~Adaptee(){}
void SpecificRequest(){cout << “ Adaptee::SpecificRequest” << endl;}
};
//适配器, public 为接口继承和实现继承,private为实现继承
class Adapter:public Target,private Adaptee
{
public:
Adapter(){;}
~Adapter(){}
void Request()
{
// do before....
Adaptee::SpecificRequest();
// do after...
}
};
//使用
int main(int argc, char** argv)
{
Target* target = new Adapter();
target->Request();
return 0;
}
4 适配器的使用场景
适配器模式使用非常广泛,非常常用。
在系统开发中,经常遇上这样的问题:在已经开发好了一套接口,或使用第三方接口,但是接口对于现在需求并不适合,需要通过一定的修改在支持,而不想改变原有的逻辑。此时,适配器就派上了用场。
使用条件:
1. 原有接口不适用客户需求
2. 客户无须只知内部实现,只知道接口。
例1:用户需求,某系统保存玩家信息。用户并不关心你使用什么数据库,只需保存玩家信息即可。设计的时候,一开始采用MYSQL 数据库,但后来又采用ORACLE数据库。这就非常适合用适配器,用Target写一套标准API给用户调用即可,对于接口基本实现由Adapter配置实现。
// 统一客户接口
class DBTarget
{
public:
virtual ~DBTarget(){}
virtual int insert(){}
virtual int delete(){}
virtual int update(){}
virtual int select(){}
}
// DBAdaptee抽象类
class DBAdaptee
{
public:
virtual ~DBAdaptee(){}
virtual int insert(){}
virtual int delete(){}
virtual int update(){}
virtual int select(){}
}
class MysqlAdaptee:public DBAdaptee{}// mysql API
class OracleAdaptee:public DBAdaptee{}// oracle ApI
class Db2Adaptee:public DBAdaptee{}//db2 Api
// 统一适配器
class Adaptor:public DBTarget
{
public:
Adaptor(DbAdaptee* adaptee){_adaptee = adaptee;}
int insert(){_adaptee->insert();}
int delete(){_adaptee->delete();}
int update(){_adaptee->update();}
int select(){_adaptee->select();}
private:
DBAdaptee* _adaptee;
};
// 使用
int main(int argc, char** argv)
{
// 配置读取
int db_type = Conf.db_type;
//工厂模式生成DBAdaptee
DBAdaptee* dbAdaptee= DBAdapteeFactory::create(dbt_type);
DBTarget* dbTarget= new Adaptor(dbAdaptee);
dbTarget->select();
dbTarget->update();
dbTarget->insert();
dbTarget->delete();
}
分析:
1. 上面DB适配器,无需修改任何代码,只需修改配置,即可支持不同数据库
2. 用户无须关心内部接口的实现
3. 如果需要新增数据库(MongoDB),只需添加MongoDBAdaptee,和工厂支持即可。
其实,上面的DB例子就是通用的DB适配器,对用户做到DB无关性。
5 总结
上面的例子,简单的讲了适配器的例子,想必都清楚适配器的优点了。我就不多说了。设计模式对于面向对象设计是博大精深。