Java 设计模式------适配器模式:从原理到3种实战的完整指南
适配器模式是一种核心的结构型设计模式,核心价值在于解决接口不兼容问题。它通过引入中间适配层,在不修改现有代码的前提下,让原本无法协作的接口实现兼容协作,因此也被称为 "包装器模式"。就像中国电器在美国使用需要电源转换插头一样,适配器模式为不同接口之间搭建了 "转换桥梁"。
文章目录
- [Java 设计模式------适配器模式:从原理到3种实战的完整指南](#Java 设计模式——适配器模式:从原理到3种实战的完整指南)
-
- 一、核心概念与实际场景
-
- [1. 模式核心含义](#1. 模式核心含义)
- [2. 典型应用场景](#2. 典型应用场景)
- 二、业务需求定义
- 三、非设计模式实现方案(反面案例)
- [四、适配器模式实战(三种实现方式)------ 手动选择适配器](#四、适配器模式实战(三种实现方式)—— 手动选择适配器)
- 五、适配器模式的适用场景
一、核心概念与实际场景
1. 模式核心含义
当系统需要调用的接口(如第三方 SDK、老系统接口)与自身期望的接口格式不匹配时,适配器模式通过定义一个适配类,将目标接口转换为系统可识别的格式,从而实现接口间的无缝协作。其核心是 "兼容现有代码,而非改造现有代码"。
2. 典型应用场景
- SpringMVC 框架:SpringMVC 支持 HTTP、WebSocket 等多种请求类型,通过HandlerAdapter适配器链,将不同类型的处理器(如@Controller方法、HttpRequestHandler)统一适配为 DispatcherServlet 可调用的接口,实现请求的统一分发。
- 多团队协作开发:智能设备项目中,硬件团队(团队 A)提供设备控制 SDK(如灯的开关接口),软件团队(团队 B)需基于统一接口控制多种硬件,通过适配器转换参数格式,隔离硬件 SDK 与上层业务逻辑。
- 第三方组件集成:使用不同厂商的支付 SDK 时,各厂商接口格式差异较大,通过适配器将其统一为系统内部的支付接口,降低集成复杂度。
- 跨平台兼容:不同操作系统(如 Windows、Linux)的文件操作接口不同,通过适配器封装差异,上层业务可调用统一接口实现跨平台兼容。
二、业务需求定义
本文以多团队协作场景为案例展开实战:
- 团队 A(硬件团队)已提供灯控 SDK,包含LightService类及对应的入参LightBO,支持灯的开关操作;
- 团队 B(软件团队)需开发上层控制系统,通过统一的设备控制接口(入参ControlDeviceBO)管理多种硬件,需通过适配器调用团队 A 的 SDK,实现灯的开关控制。
三、非设计模式实现方案(反面案例)
1. 实现思路
直接在业务层中进行参数转换和 SDK 调用,未引入适配层,将接口适配逻辑与业务逻辑混在一起。
2. 项目结构

可以看到,上边分了两个包:controldevice包和device包。controldevice包是互联网项目结构,包括controller、service等;device包可以认为是团队A给的SDK包。
3. 具体代码
控制设备入参类
java
package com.boke.desginpattern.adapter.cotroldevice.bo;
import lombok.Data;
@Data
public class ControlDeviceBO {
/**
* 设备的ID
*/
private String deviceId;
/**
* 开/关。true:开。false:关
*/
private Boolean openClose;
}
控制设备测试接口
java
package com.boke.desginpattern.adapter.cotroldevice.controller;
import com.boke.desginpattern.adapter.cotroldevice.bo.ControlDeviceBO;
import com.boke.desginpattern.adapter.cotroldevice.service.ControlDeviceService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("controlDevice")
public class ControlDeviceController {
@Resource
private ControlDeviceService controlDeviceService;
/**
* 开关灯
**/
@PostMapping("lightOpenClose")
public String lightOpenClose(@RequestBody ControlDeviceBO controlDeviceBO) {
return controlDeviceService.lightOpenClose(controlDeviceBO);
}
}
控制设备业务类
java
package com.boke.desginpattern.adapter.cotroldevice.service;
import com.boke.desginpattern.adapter.cotroldevice.bo.ControlDeviceBO;
import com.boke.desginpattern.adapter.device.bo.LightBO;
import com.boke.desginpattern.adapter.device.service.LightService;
import org.springframework.stereotype.Service;
@Service
public class ControlDeviceService {
public String lightOpenClose(ControlDeviceBO controlDeviceBO) {
System.out.println("上层:进入控制灯开关的service");
// 新建一个实际控制灯的参数
LightBO lightBO = new LightBO();
lightBO.setLightId(controlDeviceBO.getDeviceId());
lightBO.setOpen(controlDeviceBO.getOpenClose());
// 直接去控制电灯
LightService lightService = new LightService();
lightService.control(lightBO);
// 现在这种写法是最原始的写法,直接在这里进行参数的转换。
// 如果换了底层的设备,这里就要新加代码,会越来越长。所以需要使用适配器模式
return "success";
}
}
控制灯入参类
java
package com.boke.desginpattern.adapter.device.bo;
import lombok.Data;
@Data
public class LightBO {
/**
* 灯的ID
*/
private String lightId;
/**
* true:开灯。false:关灯
*/
private Boolean open;
}
控制灯业务类
java
package com.boke.desginpattern.adapter.device.service;
import com.boke.desginpattern.adapter.device.bo.LightBO;
public class LightService {
public void control(LightBO lightBO) {
System.out.println("硬件层:开始直接控制灯");
if (lightBO.getOpen()) {
System.out.printf("%s设备已开灯\n", lightBO.getLightId());
} else {
System.out.printf("%s设备已关灯\n", lightBO.getLightId());
}
}
}
测试结果
调用/controlDevice/lightOpenClose接口,传入{"deviceId":"111","openClose":false},控制台输出:
text
上层:进入控制灯开关的service
硬件层:开始直接控制灯
111设备已关灯
4. 方案优缺点
- 优点:实现简单,适合快速验证功能,能直观体现适配需求的痛点;
- 缺点:
- 适配逻辑与业务逻辑耦合,违反单一职责原则;
- 新增硬件设备时需修改业务代码,违反开闭原则,导致代码冗余臃肿;
- 直接依赖 SDK 具体实现,后续替换 SDK 需大面积修改代码。
四、适配器模式实战(三种实现方式)------ 手动选择适配器
1. 整体设计优化
(1)项目结构

(2)核心改进
- 提取统一的适配器接口,隔离上层业务与硬件 SDK;
- 三种适配器实现方式分别应对不同场景,适配逻辑独立维护;
- 业务层通过调用适配器接口实现功能,不直接依赖 SDK
可以看到,上边分了很多个包:
base包:基础的适配器接口。
adapterclass/adapterinterface/adapterobject包:适配器包,用来适配上层应用与设备层。三个包分别对适配器模式的三种写法。
controldevice包:互联网项目结构,包括controller、service等。
device包:可以认为是灯具厂商给的SDK包,直接控制设备。
2. 具体代码
控制设备入参类
java
package com.boke.desginpattern.adapterhand.cotroldevice.bo;
import lombok.Data;
@Data
public class ControlDeviceBO {
/**
* 设备的ID
*/
private String deviceId;
/**
* 开/关。true:开。false:关
*/
private Boolean openClose;
}
控制设备测试接口
java
package com.boke.desginpattern.adapterhand.cotroldevice.controller;
import com.boke.desginpattern.adapterhand.cotroldevice.bo.ControlDeviceBO;
import com.boke.desginpattern.adapterhand.cotroldevice.service.ControlDeviceService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("controlDevice")
public class ControlDeviceController {
@Resource
private ControlDeviceService controlDeviceService;
/**
* 开关灯
**/
@PostMapping("lightOpenClose")
public String lightOpenClose(@RequestBody ControlDeviceBO controlDeviceBO) {
return controlDeviceService.lightOpenClose(controlDeviceBO);
}
}
控制设备业务类
java
package com.boke.desginpattern.adapterhand.cotroldevice.service;
import com.boke.desginpattern.adapterhand.adapterclass.impl.ClassLightAdapter;
import com.boke.desginpattern.adapterhand.base.DeviceControlAdapter2;
import com.boke.desginpattern.adapterhand.adapterinterface.impl.InterfaceLightAdapter;
import com.boke.desginpattern.adapterhand.adapterobject.impl.ObjectLightAdapter;
import com.boke.desginpattern.adapterhand.base.DeviceControlAdapter;
import com.boke.desginpattern.adapterhand.cotroldevice.bo.ControlDeviceBO;
import com.boke.desginpattern.adapterhand.device.service.LightService;
import org.springframework.stereotype.Service;
@Service
public class ControlDeviceService {
public String lightOpenClose(ControlDeviceBO controlDeviceBO) {
System.out.println("上层:进入控制灯开关的service");
// 类适配器模式
DeviceControlAdapter classLightAdapter = new ClassLightAdapter();
classLightAdapter.openClose(controlDeviceBO);
// 对象适配器模式
DeviceControlAdapter objectLightAdapter = new ObjectLightAdapter(new LightService());
objectLightAdapter.openClose(controlDeviceBO);
// 接口适配器模式
DeviceControlAdapter2 interfaceLightAdapter = new InterfaceLightAdapter(new LightService());
interfaceLightAdapter.openClose(controlDeviceBO);
return "success";
}
}
控制设备适配器接口
java
package com.boke.desginpattern.adapterclass.adapter;
import com.boke.desginpattern.adapterclass.cotroldevice.bo.ControlDeviceBO;
/**
* 这里抽象出接口的好处是:
* 1.impl包可以有多个设备的适配器,外边调用时统一调本接口。
* 2.添加新的适配功能时很方便:本适配器是控制设备用的,比如:开关、设置设备。
* 如果想加一个控制设备的操作(如:设置设备的睡眠时间等)就在本接口新增一个抽象方法即可,
* 然后impl包里的具体适配器也去实现设置设备的睡眠时间的抽象方法
* 如果灯的适配器不需要实现这个抽象方法,可以再定义一个接口,新的接口继承这个接口即可
* 如果想加一个读取设备状态的适配器,直接在本接口的同级别新加一个接口即可,
* 然后impl包里的具体适配器也去实现读设备的接口
*/
public interface DeviceControlAdapter {
/**
* 开关设备
*/
void openClose(ControlDeviceBO controlDeviceBO);
}
(1)类适配器模式
使用继承的方式,将需要适配的类转换为目标接口的子类,实现目标接口的所有方法,同时继承适配类的实现,用以完成一些适配逻辑。
java
package com.boke.desginpattern.adapterclass.adapter.impl;
import com.boke.desginpattern.adapterclass.adapter.DeviceControlAdapter;
import com.boke.desginpattern.adapterclass.cotroldevice.bo.ControlDeviceBO;
import com.boke.desginpattern.adapterclass.device.bo.LightBO;
import com.boke.desginpattern.adapterclass.device.service.LightService;
public class LightAdapter extends LightService implements DeviceControlAdapter {
@Override
public void openClose(ControlDeviceBO controlDeviceBO) {
// 新建一个实际控制灯的参数
LightBO lightBO = new LightBO();
lightBO.setLightId(controlDeviceBO.getDeviceId());
lightBO.setOpen(controlDeviceBO.getOpenClose());
// 直接去控制电灯(调用LightService父类的方法)
this.control(lightBO);
}
}
(2)对象适配器模式
通过组合的方式,将适配对象与目标接口组合,实现目标接口的所有方法,并在适配类中调用需要适配对象的方法。
java
package com.boke.desginpattern.adapterhand.adapterobject.impl;
import com.boke.desginpattern.adapterhand.base.DeviceControlAdapter;
import com.boke.desginpattern.adapterhand.cotroldevice.bo.ControlDeviceBO;
import com.boke.desginpattern.adapterhand.device.bo.LightBO;
import com.boke.desginpattern.adapterhand.device.service.LightService;
public class ObjectLightAdapter implements DeviceControlAdapter {
private LightService lightService;
public ObjectLightAdapter(LightService lightService) {
this.lightService = lightService;
}
@Override
public void openClose(ControlDeviceBO controlDeviceBO) {
// 新建一个实际控制灯的参数
LightBO lightBO = new LightBO();
lightBO.setLightId(controlDeviceBO.getDeviceId());
lightBO.setOpen(controlDeviceBO.getOpenClose());
// 直接去控制电灯(调用LightService父类的方法)
lightService.control(lightBO);
}
}
(3)接口适配器模式
主要适用于需要被适配的接口中,只有用到个别接口,也就是说不需要实现它的全部接口。通过一个中间抽象类或接口实现。
控制设备适配器接口
DeviceControlAdapter2:用于解释接口适配器。
java
package com.boke.desginpattern.adapterhand.base;
import com.boke.desginpattern.adapterhand.cotroldevice.bo.ControlDeviceBO;
public interface DeviceControlAdapter2 {
/**
* 开关设备
*/
void openClose(ControlDeviceBO controlDeviceBO);
// 无用方法,仅仅用来说明接口适配器
void a();
}
中间抽象类
java
package com.boke.desginpattern.adapterhand.adapterinterface.impl;
import com.boke.desginpattern.adapterhand.base.DeviceControlAdapter2;
import com.boke.desginpattern.adapterhand.cotroldevice.bo.ControlDeviceBO;
import com.boke.desginpattern.adapterhand.device.bo.LightBO;
import com.boke.desginpattern.adapterhand.device.service.LightService;
public abstract class AbstractAdapter implements DeviceControlAdapter2 {
private LightService lightService;
public AbstractAdapter(LightService lightService) {
this.lightService = lightService;
}
@Override
public void openClose(ControlDeviceBO controlDeviceBO) {
// 新建一个实际控制灯的参数
LightBO lightBO = new LightBO();
lightBO.setLightId(controlDeviceBO.getDeviceId());
lightBO.setOpen(controlDeviceBO.getOpenClose());
lightService.control(lightBO);
}
@Override
public void a() {
}
}
灯的适配器
java
package com.boke.desginpattern.adapterhand.adapterinterface.impl;
import com.boke.desginpattern.adapterhand.cotroldevice.bo.ControlDeviceBO;
import com.boke.desginpattern.adapterhand.device.service.LightService;
public class InterfaceLightAdapter extends AbstractAdapter {
public InterfaceLightAdapter(LightService lightService) {
super(lightService);
}
@Override
public void openClose(ControlDeviceBO controlDeviceBO) {
super.openClose(controlDeviceBO);
}
}
测试结果
启动项目调用接口,后台控制台输出结果:
text
上层:进入控制灯开关的service
硬件层:开始直接控制灯
111设备已关灯
硬件层:开始直接控制灯
111设备已关灯
硬件层:开始直接控制灯
111设备已关灯
3. 三种实现方式的核心逻辑对比
实现方式 | 核心原理 | 关键依赖 | 灵活性 | 优缺点 |
---|---|---|---|---|
类适配器 | 继承适配者类(被适配的旧接口)+ 实现目标接口,通过 "继承" 复用适配者的方法 | 继承关系(单继承限制) | 低 | 优点:直接复用适配者类的方法,代码简洁;缺点:受 Java 单继承限制,无法同时适配多个适配者类;适配者类的 final 方法无法重写 |
对象适配器 | 实现目标接口 + 组合适配者对象(通过构造器注入),通过 "组合" 调用适配者的方法 | 组合关系(依赖注入) | 高 | 优点:无单继承限制,可同时适配多个适配者;适配者对象可动态替换,灵活性强;缺点:需手动调用适配者对象的方法,代码量略多 |
接口适配器 | 定义包含多个方法的目标接口 → 提供抽象类实现该接口(空实现所有方法)→ 具体适配器继承抽象类,仅重写需要的方法 | 抽象类(空实现中间层) | 中 | 优点:解决 "目标接口方法过多,仅需使用部分方法" 的场景,避免代码冗余;缺点:仅适用于 "目标接口方法数量多且部分方法无需实现" 的场景,通用性较弱 |
五、适配器模式的适用场景
- 重用现有的代码 :适配器模式可以允许我们重用已有的类或接口 ,而不需要修改其原有的代码。
- 集成老系统 :当现有的系统不满足用户需求 时,需要增加系统功能或接口 。但是,老系统的接口可能与现有的技术、平台不兼容,此时可以采用适配器模式,将现有的接口适配为新的接口,从而实现新系统的集成。
- 集成第三方组件 :在使用第三方组件时,可能由于它们实现的 API 不同而导致应用程序复杂,此时可以使用适配器模式,将第三方组件提供的 API 适配为自己需要的 API,方便在应用程序中进行调用。
- 实现跨平台兼容 :在不同平台、不同技术栈之间进行开发时,常常需要适配不同的接口,以使得不同的平台或技术栈之间能够相互兼容 ,此时可以使用适配器模式来处理各种不兼容问题。