什么是C++适配器模式
C++适配器模式属于结构型设计模式的一种,核心作用是把一个类的接口转换成客户端期望的另一个接口,让原本因为接口不兼容而无法一起工作的类可以协同工作。这种模式在实际开发中非常实用,比如对接旧系统接口、适配第三方库接口等场景都能用到。
适配器模式的核心角色
适配器模式主要包含三个核心角色,每个角色的职责划分非常清晰:
- 目标接口(Target):客户端期望使用的接口,定义了客户端需要调用的方法规范。
- 适配者(Adaptee):需要被适配的原有类,拥有完整的业务功能,但接口不符合目标接口的要求。
- 适配器(Adapter):核心转换角色,实现目标接口,同时持有适配者的实例或者继承适配者,负责将目标接口的调用转换为对适配者对应方法的调用。
C++适配器模式的两种实现方式
1. 类适配器实现
类适配器通过多重继承的方式实现,适配器类同时继承目标接口和适配者类,直接在适配器的方法中调用父类(适配者)的方法完成接口转换。
首先定义目标接口,假设我们需要一个能输出字符串长度的目标接口:
// 目标接口,定义客户端期望的方法
class Target {
public:
virtual ~Target() {}
// 客户端期望调用的方法,获取内容长度
virtual int getContentLength() = 0;
};
// 适配者类,原有功能类,接口不符合目标要求
class Adaptee {
public:
// 原有方法,返回内容字符串
std::string getContent() {
return "适配器模式测试内容";
}
};
// 类适配器,同时继承Target和Adaptee
class ClassAdapter : public Target, public Adaptee {
public:
int getContentLength() override {
// 调用适配者的原有方法,转换为目标接口要求的返回值
std::string content = getContent();
return content.length();
}
};
客户端调用方式如下:
#include <iostream>
#include <string>
int main() {
Target* target = new ClassAdapter();
std::cout << "内容长度:" << target->getContentLength() << std::endl;
delete target;
return 0;
}
2. 对象适配器实现
对象适配器采用组合的方式实现,适配器类实现目标接口,同时持有适配者的实例,通过调用适配者实例的方法完成接口转换,这种方式更符合合成复用原则。
目标接口和适配者类与类适配器场景一致,适配器实现如下:
// 对象适配器,继承Target,持有Adaptee实例
class ObjectAdapter : public Target {
private:
Adaptee* adaptee;
public:
// 构造函数传入适配者实例
ObjectAdapter(Adaptee* ad) : adaptee(ad) {}
int getContentLength() override {
// 调用适配者实例的方法完成转换
std::string content = adaptee->getContent();
return content.length();
}
~ObjectAdapter() {
delete adaptee;
}
};
客户端调用方式如下:
#include <iostream>
#include <string>
int main() {
Adaptee* adaptee = new Adaptee();
Target* target = new ObjectAdapter(adaptee);
std::cout << "内容长度:" << target->getContentLength() << std::endl;
delete target;
return 0;
}
两种实现方式的对比
类适配器和对象适配器各有适用场景,我们可以通过下表对比两者的区别:
| 对比维度 | 类适配器 | 对象适配器 |
|---|---|---|
| 实现方式 | 多重继承,继承适配者类 | 组合方式,持有适配者实例 |
| 灵活性 | 适配者是固定的,不够灵活 | 可以动态传入不同的适配者实例,灵活性更高 |
| 耦合度 | 与适配者类强耦合 | 与适配者类松耦合 |
| 适用场景 | 适配者类稳定,不需要频繁扩展 | 适配者可能变化,或者需要适配多个不同的适配者 |
适配器模式的使用注意事项
虽然适配器模式能很好地解决接口兼容问题,但也不建议过度使用。如果系统中有大量接口不兼容的情况,说明系统设计可能存在问题,此时应该优先优化原有接口设计,而不是大量使用适配器来补救。另外,适配器模式本身会增加系统的复杂度,新增了额外的类,需要在灵活性和复杂度之间做好平衡。