适配器模式是什么
把不兼容的接口转成调用方期望的接口,让两套既有代码在不改对方的前提下协作。典型对象是第三方 SDK、遗留模块、异构协议。形态上对象适配(组合)优先于类适配(多重继承),因为组合不占继承位、也更容易替换实现与在测试里换桩。适配器只做转换与错误映射,它是防腐层最常见的具体做法:外部模型的变动被挡在边界之外。
基本信息
| 意图 | 接口转换、屏蔽不兼容 |
|---|---|
| 形态 | 对象适配(组合,优先)/ 类适配(多重继承) |
| 边界 | 只做翻译与错误映射,不含业务规则 |
| 位置 | 系统边界、依赖方向向内的收口处 |
| 命名 | 按被适配对象命名(SmsAdapter),而不是按模式命名 |
典型使用场景
- 包装第三方短信、支付、地图 API,隔离它们的参数风格与错误码
- 让遗留系统的旧接口符合新代码的领域接口
- 同一能力接多家供应商时,为每家写一个适配器,上层只认统一接口
- 把不同格式(JSON、XML、CSV)的输入统一成内部模型
- 测试环境用内存实现替换真实客户端,接口不变
- 新旧接口并行期让两套签名同时可用,逐步迁移调用方
Java 示例
Java 示例
public interface Notifier { void send(String to, String text); }
class SmsAdapter implements Notifier {
private final ThirdPartySms sms; // 组合,不继承
SmsAdapter(ThirdPartySms sms) { this.sms = sms; }
@Override
public void send(String to, String text) {
try {
sms.dispatch(to, text, "utf-8");
} catch (SmsException e) {
throw new NotifyFailedException(to, e); // 错误模型也一起翻译
}
}
}与邻近模式的区别
| 模式 | 目的 | 接口 |
|---|---|---|
| Adapter | 转换接口,让不兼容的能对接 | 变成调用方期望的形状 |
| Facade | 简化入口,降低客户端认知负担 | 新开一个更简单的接口 |
| Decorator | 在保持接口的前提下叠加行为 | 接口不变 |
| Proxy | 同一接口的替身,控制访问 | 接口不变 |
| Bridge | 抽象与实现各自独立扩展 | 两侧都是自定义的 |
适配器应当薄且可测:转换规则集中在一处,用桩替换第三方即可单测。如果适配器里开始出现重试编排、缓存策略、业务判断,说明它已经越界成服务层,该把那些逻辑挪到更合适的位置。
适配器的有效范围通常只覆盖一个方向。上下游都需要转换时,写两个方向明确的适配器比写一个双向类更好维护:双向类容易把两套模型揉成一团,最后看不出谁在依赖谁。