在C++开发里,适配器模式是一种结构型设计模式,用来把一个类的接口变成客户端需要的另一种接口。当旧接口和新规范不一致时,通过适配器封装可以避免改动原有代码,同时让新模块正常调用。

一、C++适配器模式的常见应用场景
适配器模式并不是凭空发明,而是解决实际兼容问题的手段。下面是几种典型场景:
- 接入第三方库:第三方提供的C接口或旧版C++类不符合当前项目的抽象层规范。
- 遗留系统重构:老系统接口杂乱,新业务层不希望直接依赖旧实现。
- 多版本接口统一:同一功能有多个历史版本接口,用适配器对外暴露一致调用方式。
- 测试桩替换:用适配器把真实服务换成模拟实现,方便单元测试。
二、用类适配器兼容旧接口
类适配器通过私有继承旧类、实现新接口来完成转换。下面示例展示旧日志接口和新日志接口如何兼容。
#include <iostream>
#include <string>
// 旧接口:遗留日志类
class OldLogger {
public:
void writeLog(const std::string& msg) {
std::cout << "OldLog: " << msg << std::endl;
}
};
// 新接口:项目统一要求的日志抽象
class ILogger {
public:
virtual void log(const std::string& text) = 0;
virtual ~ILogger() {}
};
// 类适配器:继承旧类并实现新接口
class LoggerAdapter : private OldLogger, public ILogger {
public:
void log(const std::string& text) override {
// 把新接口调用转给旧接口
writeLog(text);
}
};
int main() {
ILogger* logger = new LoggerAdapter();
logger->log("系统启动");
delete logger;
return 0;
}
三、用对象适配器更灵活地封装
对象适配器把旧对象作为成员,比类适配器耦合更低,也支持适配多个旧实例。
#include <iostream>
#include <string>
class OldLogger {
public:
void writeLog(const std::string& msg) {
std::cout << "OldLog: " << msg << std::endl;
}
};
class ILogger {
public:
virtual void log(const std::string& text) = 0;
virtual ~ILogger() {}
};
// 对象适配器:持有旧对象指针
class LoggerObjectAdapter : public ILogger {
OldLogger* old;
public:
LoggerObjectAdapter(OldLogger* o) : old(o) {}
void log(const std::string& text) override {
old->writeLog(text);
}
};
int main() {
OldLogger old;
ILogger* logger = new LoggerObjectAdapter(&old);
logger->log("业务处理完成");
delete logger;
return 0;
}
四、用模板适配器减少重复代码
如果多种旧类型都有相似成员函数,可以用模板写出通用适配器。
#include <iostream>
#include <string>
class ILogger {
public:
virtual void log(const std::string& text) = 0;
virtual ~ILogger() {}
};
// 模板适配器:要求旧类型有 writeLog 方法
template <typename T>
class TemplateAdapter : public ILogger {
T* target;
public:
TemplateAdapter(T* t) : target(t) {}
void log(const std::string& text) override {
target->writeLog(text);
}
};
class AnotherOldLogger {
public:
void writeLog(const std::string& m) {
std::cout << "Another: " << m << std::endl;
}
};
int main() {
AnotherOldLogger a;
ILogger* logger = new TemplateAdapter<AnotherOldLogger>(&a);
logger->log("模板适配");
delete logger;
return 0;
}
五、选择建议
在C++中封装旧接口时,若旧类不常被替换,类适配器写法简单;若需要运行时切换不同旧实现,对象适配器更合适;当旧类型较多且接口相似,模板能减少冗余。无论哪种方式,适配器都让新代码只依赖统一接口,降低重构风险。