一 简介
适配器(Adapter )模式, 就是定义一个第三方封装类,将一个类的接口转换成客户期望的另外一个接口,使得原本由于接口不兼容导致不能一起工作的类可以一起工作。 比如,现在有一根Micro USB接口的数据线,而手机接口是Type-C,两者不能直接使用;通过一个Micro USB转Type-C的适配头即可进行使用。
适配器模式根据实现过程的不同,分为类模型适配器和对象模型适配器。
- 类模型适配器:通过接口继承实现,适配器与适配者之间是继承(实现)关系
- 对象模型适配器:通实现继承实现,适配器与适配者之间是关联关系;对象模型适配器使用较多
接口继承和实现继承是面向对象领域的两个重要的概念: 接口继承,指的是通过继承,子类获得了父类的接口
实现继承,指的是通过继承,子类获得了父类的实现
二 UML图
- Target(目标抽象类):目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。
- Adapter(适配器类):适配器可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系
- Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下可能没有适配者类的源代码。
根据对象适配器模式结构图,在对象适配器中,客户端需要调用request()方法,而适配者类Adaptee没有该方法,但是它所提供的specificRequest()方法却是客户端所需要的。为了使客户端能够使用适配者类,需要提供一个包装类Adapter,即适配器类。这个包装类包装了一个适配者的实例,从而将客户端与适配者衔接起来,在适配器的request()方法中调用适配者specificRequest()方法。因为适配器类与适配者类是关联关系(也可称之为委派关系),所以这种适配器模式称为对象适配器模式。
三 例子
//用户目标类 Paint
/* 目标接口类,客户期望的接口 */
class Paint
{
public:
Paint();
virtual ~Paint();//防止资源泄露
virtual void paint();
};
Paint::Paint()
{
}
Paint::~Paint()
{
}
void Paint::paint()
{
cout << "Paint::paint()" << endl;
}
//声明待适配类SpecialPaint
/* 需要适配的类 */
class SpecialPaint
{
public:
SpecialPaint();
~SpecialPaint();
void specialPaint();
};
SpecialPaint::SpecialPaint()
{
}
SpecialPaint::~SpecialPaint()
{
}
void SpecialPaint::specialPaint()
{
cout << "SpecialPaint::specialPaint()" << endl;
}
//声明适配器类 Adaptee
/* 类模型适配器类,通过public继承获得接口继承的效果,通过private继承获得实现继承的效果 */
class Adaptee :public Paint,private SpecialPaint
{
public:
Adaptee();
~Adaptee();
virtual void paint();/* 期望接口实现 */
};
Adaptee::Adaptee()
{
}
Adaptee::~Adaptee()
{
}
void Adaptee::paint()
{
/* 重写父类方法,并通适配类对象调用适配类方法 */
SpecialPaint::specialPaint();
}
int main()
{
//类适配器模式
//类模型适配器,即是通过接口继承方式实现,将适配类接口转换为用户期望接口。
//此时,适配器与适配者之间是继承关系
Paint * paint = new Adaptee();
paint->paint();
delete paint;
getchar();
return 0;
}
结果
四 优缺点
优点:
- 解耦: 目标类与适配者解耦,通过引入一个适配器类来复用现有的适配者类,无须修改原有结构代码。
- 类透明性:将具体的业务实现过程封装在适配者类中,对于客户端类来说是透明的。
- 复用性: 系统需要使用现有的类,而此类的接口不符合系统的需要。那么通过适配器模式可以将其他类封装为系统需要的类,实现功能更好的复用;此外,同一个适配者类可以在多个不同的系统中复用。
- 灵活性好和易于拓展:无需更改用户接口和适配者代码,易于拓展,符合“开闭原则“。
缺点:
- 可能导致软件架构凌乱, 过多的使用适配器,会让软件系统非常零乱,不易对软件框架整体进行把控。
五 使用场景
适配器模式的优点决定了其适用的场景,反过来其缺点即是其不适用的场景。适配器模式适用场景:
用户需要复用已有类(模块),而该模块的接口与复用环境要求不一致,可以使用适配器模式将该模块适配到用户适合的接口
多个组件功能类似,但接口不统一且可能会经常切换,可使用适配器模式,使得客户可以以统一的接口使用这些组件。如:
使用第三方库,将库接口适配到自己的系统中,算法、支付、加密等复用公司内部开发的成熟模块软件架构更新(接口有变动),但需兼容旧的软件模块将日志模块输出到串口重定向输出到U盘、网口等网络模块统一以太网、WiFi、蜂窝网、蓝牙等接口