一、示例场景
在日常开发里,经常会遇到这么一个尴尬场景:
你要用的库早就存在了,而且功能挺好用,但它的接口风格和你项目里约定的完全不一样。
这时候怎么办?直接在业务代码里写一堆兼容代码?以后换库的时候全项目大面积改动?
------这就是典型的"接口不对路"的问题。
适配器模式(Adapter)就是专门解决这个问题的,它的作用就一句话:
把"不兼容"的接口用一个中间层翻译一下,让它能无缝接入到现有系统。
假设我们有一个老的日志库 OldLogger
,只能用 logMessage(std::string)
来写日志。
但在项目中,我们已经约定使用统一接口 ILogger
,提供 info()
、error()
方法。
我们不希望在业务里到处写 logMessage("[INFO] ...")
,所以需要用适配器来包装。
二、类图

三、代码实现
通过 LoggerAdapter
把旧的 OldLogger
包装成统一的 ILogger
接口,让客户端代码可以直接用 info()
和 error()
方法,而不用关心底层的老接口。
cpp
#include <iostream>
#include <string>
// 目标接口(Target)
struct ILogger {
virtual ~ILogger() = default;
virtual void info(const std::string& msg) = 0;
virtual void error(const std::string& msg) = 0;
};
// 遗留类(Adaptee)
class OldLogger {
public:
void logMessage(const std::string& text) {
std::cout << "[OldLogger] " << text << std::endl;
}
};
// 适配器(Adapter)
class LoggerAdapter : public ILogger {
public:
LoggerAdapter(OldLogger& old) : oldLogger_(old) {}
void info(const std::string& msg) override {
oldLogger_.logMessage("[INFO] " + msg);
}
void error(const std::string& msg) override {
oldLogger_.logMessage("[ERROR] " + msg);
}
private:
OldLogger& oldLogger_;
};
// 客户端(Client)
int main() {
OldLogger legacy;
LoggerAdapter logger(legacy);
logger.info("system started");
logger.error("something went wrong");
return 0;
}
输出结果
cpp
[OldLogger] [INFO] system started
[OldLogger] [ERROR] something went wrong
四、使用体会
适配器模式在代码里看上去并不复杂,就是多写一个类包一层。
但它的价值不在代码量,而在解耦:
-
业务代码只依赖统一的接口,不和遗留库绑死;
-
将来如果换成别的日志库,只要改适配器实现,业务完全不用动;
-
旧接口和新接口的差异,都集中在适配器里消化掉了。
这也是我喜欢的一点:适配器就是专门处理"接口不统一"这个麻烦的。
五、总结
适配器模式本质上就是"旧瓶装新酒":
-
瓶子是新接口(
ILogger
), -
酒是旧实现(
OldLogger
), -
适配器就是把酒灌进新瓶子的过程。
下次遇到类似场景时,不妨先想一想是不是可以写个 Adapter,把问题收敛到一个地方去处理。这样以后维护起来,心态会轻松很多。