适配器模式(Adapter Pattern)定义如下:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
适配器模式分为类结构型模式和对象结构型模式两种,前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。
在软件设计中也可能出现:需要开发的具有某种业务功能的组件在现有的组件库中已经存在,但它们与当前系统的接口规范不兼容,如果重新开发这些组件成本又很高,这时用适配器模式能很好地解决这些问题。
适配器模式的组成如下:
| 组成 | 描述 |
|---|---|
| Target(目标接口) | 当前系统业务所期待的接口,它可以是抽象类或接口 |
| Adaptee(适配者) | 需要适配的接口 |
| Adapter(适配器) | 它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者 |
类适配器模式结构图如下:

从上图可以看出:
- 问题:Target想调用request方法,但是adaptee并没有这个方法(不兼容)
- 解决方法:提供中间件Adapter类,使其实现Target接口,把Adaptee的API和Target的API衔接起来
对象适配器模式结构体如下:

将适配者Adaptee传入适配器Adapter中,将两者的API衔接调用。
适配器模式的优点
- 客户端通过适配器可以透明地调用目标接口
- 复用了现存的类,程序员不需要修改原有代码而重用现有的适配者类
- 将目标类和适配者类解耦,解决了目标类和适配者类接口不一致的问题
- 在很多业务场景中符合开闭原则
适配器模式的缺点
- 适配器编写过程需要结合业务场景全面考虑,可能会增加系统的复杂性
- 增加代码阅读难度,降低代码可读性,过多使用适配器会使系统代码变得凌乱
适配器模式应用场景
- 以前开发的系统存在满足新系统功能需求的类,但其接口同新系统的接口不一致
- 使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同
适配器模式使用步骤
- 实现目标接口
- 内部持有一个待转换接口的引用
- 在目标接口的实现方法内部,调用待转换接口的方法
适配器模式使用示例
假设我们已经有一个Task类,实现了Callable接口,现在想使用一个Thread去运行Task,那么就需要将Callable转换为Runnable接口来使用。这就是使用Adapter模式将Callable接口适配为Runnable。
public class AdapterTest {private static class Task implements Callable<String> {String params;public Task(String params) {this.params = params;}@Overridepublic String call() {int length = params.length();if (length > 10) {return params.substring(5);}return params;}}private static class RunnableAdapter implements Runnable {private Task task;private RunnableAdapter(Task task) {this.task = task;}@Overridepublic void run() {String call = task.call();System.out.println("result:" + call);}}public static void main(String[] args) {// 报错:参数类型不对// Thread thread = new Thread(new Task("bujianjunxi"));// 通过适配器调用Task task = new Task("bujianjunxi");RunnableAdapter adapter = new RunnableAdapter(task);adapter.run();}}
程序运行结果如下:
:::success result:njunxi :::
与外观模式的区别
- 外观模式的实现核心主要是——由外观类去保存各个子系统的引用,实现由一个统一的外观类去包装多个子系统类,然而客户端只需要引用这个外观类,然后由外观类来调用各个子系统中的方法。
- 适配器模式是将一个对象包装起来以改变其接口,而外观是将一群对象 ”包装“起来以简化其接口。它们的意图是不一样的,适配器是将接口转换为不同接口,而外观模式是提供一个统一的接口来简化接口。
