适配器模式
适配器模式(Adapter Pattern)是一种结构型设计模式,它把一个类的接口转换成客户端期待的另一种接口,使原本因接口不兼容而无法协作的类能够一起工作。该模式在二十世纪九十年代由“四人帮”归纳进面向对象设计模式的经典体系中,常用于复用现有组件、对接第三方类库以及改造正在运行的系统,而不必修改原有代码。
定义
适配器模式是指把一个类的接口变换成客户端所期望的另一种接口,让原本因接口不匹配而无法在一起工作的两个类可以协同工作[1]。它的出发点是兼容性,而不是创造新功能:被复用的组件本身往往已经存在并且可用,问题只在于它的调用方式与当前系统的规范对不上。
该模式通常涉及4个角色,即客户端、目标接口、适配者和适配器。目标是客户端希望使用的接口,适配者是需要被转换的现存组件,适配器则是二者之间的转换器,客户端只依赖目标接口,通过它间接调用适配者的能力。按照实现手段的不同,适配器模式可分为类适配器与对象适配器2种形态[2]。
原理
适配器的核心是一层接口转换代码。客户端按目标接口发起调用,适配器接收到调用后,把方法名、参数或数据结构翻译成适配者能够接受的形式,再转交给适配者执行,最后把结果转换回目标接口约定的形式返回。整个过程中,适配者的源码不需要改动,客户端也不需要知道适配者的存在[3]。
类适配器依靠继承实现。适配器类同时继承适配者并实现目标接口,因此继承了适配者的全部方法,把目标接口中的方法改写为对适配者方法的调用。C++等支持多重继承的语言可以直接让适配器类同时继承目标与适配者;Java不支持多继承,只能以继承适配者、实现目标接口的方式变通。
对象适配器依靠组合实现。适配器类实现目标接口,同时在内部持有一个适配者对象的引用,把目标方法委托给该对象。由于不涉及继承,一个适配器可以对适配者本身及其子类一并生效,组合关系也比继承更加灵活,因此在多数场景下被优先采用[2]。
classDiagram
class Client
class Target {
<<interface>>
+request()
}
class Adapter {
-adaptee: Adaptee
+request()
}
class Adaptee {
+specificRequest()
}
Client --> Target
Target <|.. Adapter
Adapter --> Adaptee
适配器模式还有一种扩展形态,即双向适配器。双向适配器同时持有目标方与适配者方,既能把适配者接口转成目标接口,也能反向把目标接口转成适配者接口,用于两个方向都需要互调的场景[4]。
发展历程
适配器模式作为成文的模式条目,最早出现在1994年出版的《设计模式:可复用面向对象软件的基础》一书中。该书的4位作者埃里希·伽玛、理查德·赫尔姆、拉尔夫·约翰逊和约翰·弗利赛德斯被合称为“四人帮”(Gang of Four,GoF),书中收录的23种设计模式也因此被称为“四人帮设计模式”[5]。
在该书的分类框架中,设计模式按目的分为创建型、结构型和行为型3类,适配器模式被归入结构型。结构型模式共有7种,除适配置模式外还包括桥接、装饰、组合、外观、享元和代理,它们共同关注类和对象如何组合成更大的结构。此后的实践普遍把适配器看作一种补救性手段:它主要出现于系统后期扩展或改造阶段,而不是在全新系统的详细设计中主动引入。
应用
遗留系统改造是适配器模式的典型用途。当已有组件满足新的业务需求,但接口与现行规范不一致,而重写组件的代价又较高时,可以增加一个适配器把旧接口包装成新接口,从而在不改动原有代码的前提下复用这部分能力。以文档处理为例,系统中已有能处理某一种格式文档的组件,若要让其同时支持另一种格式,可以针对格式差异编写适配器,把新格式的调用转换为旧组件能够执行的操作。
对接第三方类库时也常引入适配器。应用与外部类库之间加一层适配器,应用只依赖自身定义的目标接口,类库被隔离在适配器之后;日后更换类库,只需替换适配器实现,应用代码基本不受影响[3]。Dart、Flutter 等语言与框架的资料中,同样把这种包装第三方接口的做法列为适配器模式的常见使用场景[2]。
在一些框架内部也能看到该模式的结构。Spring MVC对请求的处理依赖适配器机制:控制器(Controller)有多种类型,各自的处理方法并不相同,框架通过统一的处理器适配器接口调用不同类型控制器的方法,避免在分发逻辑中逐一判断控制器类型。Android 的列表控件同样采用类似思路,把多种形式的条目描述转换为列表控件能够识别的视图对象[2]。
局限
适配器模式增加了系统中的间接层次。调用方看到的是目标接口,实际执行的是被包装的适配者,代码阅读时需要跨过适配器才能追溯到真实实现;适配器用得过多,调用链会变得零散,整体结构不易把握。因此在该模式并不必要时,直接重构系统往往比叠加适配器更可取。
2种实现形态各有约束。类适配器依赖继承,在只支持单继承的语言中一次只能适配一个适配者,并且无法把一个适配者及其子类一并适配到目标接口[6]。对象适配器的适配范围更宽,但若要替换适配者已有的某个方法就较为麻烦,通常得先为适配者建立子类并重写相应方法,再让适配器引用这个子类[6]。
适配器只改变调用的形式,并不改变被适配组件本身的行为和能力边界。接口语义差异过大、或者双方在数据含义上并不对应时,一层转换无法弥补,此时需要的是重新设计接口或重构原有组件,而不是继续增加适配层。
参见
参考资料
- 从零开始学设计模式(六)—适配器模式(Adapter Pattern) [引用日期2026-10-29]
- 灵动的适配器模式 [引用日期2026-10-29]
- --- [引用日期2026-10-29]
- 适配器模式(Adapter) [引用日期2026-10-29]
- 设计模式:可复用面向对象软件的基础 [引用日期2026-10-29]
- 从零开始学设计模式(六):适配器模式(Adapter Pattern) [引用日期2026-10-29]