[1. 模式说明](#1. 模式说明)
[2. 模式原理](#2. 模式原理)
[2.1 类的适配器模式](#2.1 类的适配器模式)
[2.2 对象的适配器模式](#2.2 对象的适配器模式)
1. 模式说明
适配器模式(Adapter Pattern)是一种结构型设计模式,它允许将一个接口转换成客户端所期望的另一种接口。适配器模式的核心思想是通过创建一个中间层(适配器),使得原本由于接口不兼容而无法一起工作的类可以协同工作。
适配器模式有两种主要形式:
-
类适配器:通过继承来实现适配。
-
对象适配器:通过组合来实现适配,更常用且更灵活。
2. 模式原理
2.1 类的适配器模式
类的适配器模式是把适配的类的API转换成为目标类的API。
2.1.1 UML类图 & 组成
在上图中可以看出:
- 冲突:Target期待调用Request方法,而Adaptee并没有(这就是所谓的不兼容了)。
- 解决方案:为使Target能够使用Adaptee类里的SpecificRequest方法,故提供一个中间环节Adapter类**(继承Adaptee & 实现Target接口)**,把Adaptee的API与Target的API衔接起来(适配)。
Adapter与Adaptee是继承关系,这决定了这个适配器模式是类的
2.1.3 实例讲解
cpp
// 目标接口 (原接口,不想修改)
class Target {
public:
virtual void request() = 0;
};
// 被适配类 (新接口)
class Adaptee {
public:
void specificRequest() {
std::cout << "Adaptee specific request" << std::endl;
}
};
新接口的名字specificRequest不一样了,不能被原代码直接调用。搞一个类适配器包裹封装(适配)出原来的接口:->request()
// 类适配器
class Adapter : public Target, public Adaptee { // 继承Target和Adaptee
public:
void request() override {
specificRequest(); // 调用Adaptee的方法
}
};
通过适配器,可以用原来的调用代码target->request() 调用新功能:
int main() {
Target* target = new Adapter();
target->request(); // 输出: Adaptee specific request
delete target;
return 0;
}
在main
函数中,我们创建了一个Adapter
对象,并通过Target
指针来调用其request
方法。由于Adapter
实现了Target
接口,并且在其request
方法中调用了Adaptee
的specificRequest
方法,所以客户端代码可以透明地使用Target
接口,而不需要关心底层的Adaptee
实现。
2.2 对象的适配器模式
与类的适配器模式相同,对象的适配器模式也是把适配的类的API转换成为目标类的API。
与类的适配器模式不同的是,对象的适配器模式不是使用继承关系连接到Adaptee类,而是使用委派关系连接到Adaptee类。
2.2.1 UML类图
在上图中可以看出:
• 冲突:Target期待调用Request方法,而Adaptee并没有(这就是所谓的不兼容了)。
• 解决方案:为使Target能够使用Adaptee类里的SpecificRequest方法,故提供一个中间环节Adapter类(包装了一个Adaptee的实例),把Adaptee的API与Target的API衔接起来(适配)。
Adapter与Adaptee是委派关系,这决定了适配器模式是对象的。
2.2.2 实例讲解
cpp
// 目标接口 (原接口,不想改)
class Target {
public:
virtual void request() = 0;
};
// 被适配类 (新接口)
class Adaptee {
public:
void specificRequest() {
std::cout << "Adaptee specific request" << std::endl;
}
};
创建适配器(但是不继承Target和Adaptee,而是在其中创建新接口的对象)
// 适配器类(对象适配器)
class Adapter : public Target {
public:
Adapter(Adaptee* adaptee) : m_adaptee(adaptee) {}
void request() override {
m_adaptee->specificRequest();
}
private:
Adaptee* m_adaptee;
};
原代码中创建适配器,就可以使用原来的接口调用新功能 target->request()
int main() {
Adaptee* adaptee = new Adaptee();
Target* target = new Adapter(adaptee);
target->request();
delete target;
delete adaptee;
return 0;
}
两种方式的优缺点
3.2 类的适配器模式
优点
• 使用方便,代码简化
仅仅引入一个对象,并不需要额外的字段来引用Adaptee实例
缺点
• 高耦合,灵活性低
使用对象继承的方式,是静态的定义方式

3.3 对象的适配器模式
优点
• 灵活性高、低耦合
采用 "对象组合"的方式,是动态组合方式
缺点
• 使用复杂
需要引入对象实例
特别是需要重新定义Adaptee行为时需要重新定义Adaptee的子类,并将适配器组合适配