Java适配器模式介绍与实现示例 - 指南

news/2025/9/25 14:11:10/文章来源:https://www.cnblogs.com/tlnshuju/p/19111102

Java适配器模式介绍与实现示例 - 指南

2025-09-25 14:10  tlnshuju  阅读(0)  评论(0)    收藏  举报

文章目录

  • Java适配器模式介绍与实现示例
    • 什么是适配器模式?
    • 适配器模式的类型
    • 应用场景
    • 实现示例-1
      • 示例场景
      • 1. 定义目标接口
      • 2. 定义需要适配的类
      • 3. 创建适配器
      • 4. 实现目标接口的具体类
      • 5. 测试代码
      • 输出结果
    • 类适配器示例(使用继承)
    • 实现示例-2
      • 多个平台对接处理业务逻辑不一致,通过匹配url路径做处理
      • 入口(Controller)
      • 默认消息处理
      • 业务处理适配器
      • 事件处理器1
      • 事件处理器2
      • 业务处理实现
        • 1、设备告警
        • 2、设备状态
    • 优点
    • 缺点

Java适配器模式介绍与实现示例

什么是适配器模式?

适配器模式(Adapter Pattern)是一种结构型设计模式,它允许不兼容的接口之间能够协同工作。适配器充当两个不兼容接口之间的桥梁,将一个类的接口转换成客户端期望的另一个接口。

适配器模式的类型

  1. 类适配器:通过继承来实现适配
  2. 对象适配器:通过组合来实现适配(更常用)

应用场景

实现示例-1

示例场景

假设我们有一个旧的媒体播放器只能播放MP3文件,但现在我们想要支持播放MP4和VLC格式的文件。

1. 定义目标接口

// 目标接口:新媒体播放器
public interface MediaPlayer {
void play(String audioType, String fileName);
}

2. 定义需要适配的类

// 需要适配的类:高级媒体播放器接口
public interface AdvancedMediaPlayer {
void playVlc(String fileName);
void playMp4(String fileName);
}
// VLC播放器实现
public class VlcPlayer
implements AdvancedMediaPlayer {
@Override
public void playVlc(String fileName) {
System.out.println("Playing vlc file: " + fileName);
}
@Override
public void playMp4(String fileName) {
// 什么也不做
}
}
// MP4播放器实现
public class Mp4Player
implements AdvancedMediaPlayer {
@Override
public void playVlc(String fileName) {
// 什么也不做
}
@Override
public void playMp4(String fileName) {
System.out.println("Playing mp4 file: " + fileName);
}
}

3. 创建适配器

// 媒体适配器类
public class MediaAdapter
implements MediaPlayer {
private AdvancedMediaPlayer advancedMusicPlayer;
public MediaAdapter(String audioType) {
if (audioType.equalsIgnoreCase("vlc")) {
advancedMusicPlayer = new VlcPlayer();
} else if (audioType.equalsIgnoreCase("mp4")) {
advancedMusicPlayer = new Mp4Player();
}
}
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("vlc")) {
advancedMusicPlayer.playVlc(fileName);
} else if (audioType.equalsIgnoreCase("mp4")) {
advancedMusicPlayer.playMp4(fileName);
}
}
}

4. 实现目标接口的具体类

// 具体播放器实现
public class AudioPlayer
implements MediaPlayer {
private MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
// 内置支持播放MP3文件
if (audioType.equalsIgnoreCase("mp3")) {
System.out.println("Playing mp3 file: " + fileName);
}
// 使用适配器支持其他格式
else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
} else {
System.out.println("Invalid media type: " + audioType);
}
}
}

5. 测试代码

public class AdapterPatternDemo
{
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "song.mp3");
audioPlayer.play("mp4", "movie.mp4");
audioPlayer.play("vlc", "series.vlc");
audioPlayer.play("avi", "video.avi");
}
}

输出结果

Playing mp3 file: song.mp3
Playing mp4 file: movie.mp4
Playing vlc file: series.vlc
Invalid media type: avi

类适配器示例(使用继承)

// 类适配器通过继承来实现
public class ClassMediaAdapter
extends Mp4Player implements MediaPlayer {
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("mp4")) {
playMp4(fileName);
} else {
System.out.println("Invalid media type for this adapter: " + audioType);
}
}
}

实现示例-2

多个平台对接处理业务逻辑不一致,通过匹配url路径做处理

入口(Controller)

/**
* @desc 云平台接口接收数据改造
* @author: kele
* @desc:
*/
@RestController
@RequestMapping("/interface")
@Log4j2
public class QiyCloudInterfaceController
{
private final Map<
String, IMessageHandleService> messageHandleServiceMap = SpringUtil.getBeansOfType(IMessageHandleService.class)
;
private final IMessageHandleService defaultMessageHandleService = SpringUtil.getBean(DefaultMessageHandleService.class)
;
private static final String IP_UTILS_FLAG = ",";
@Autowired
private IpWhiteListConfig ipWhiteListConfig;
@PostMapping("/{type}")
public Object alarmMessage(@PathVariable("type") String type, @RequestBody(required = false) Object object) {
String ipAddress = getIpAddress();
log.info("type:{} ip:{}, 接受到的数据为{}", type, ipAddress, JSON.toJSONString(object));
/*暂时屏蔽掉
if (!ipWhiteListConfig.getWhiteList().contains(ipAddress)){
log.error("ip:{} whitelist restriction", ipAddress);
return R.failed("ip:"+ ipAddress +" whitelist restriction");
}*/
try {
/* type数据格式 platform_messageType-dataSource
* 数据可能存在以下几种格式:
* (1) platform_messageType-dataSource
* (2) platform-dataSource
* (3) platform_messageType
* (4) platform
*/
String platform, messageType = "", dataSource = "";
//先用中划线分割
String[] typeSplits = type.split(StrUtil.DASHED);
String platformMessageType = typeSplits[0];
//存在中划线,说明指定了dataSource
if (typeSplits.length >
1) {
dataSource = typeSplits[1];
}
String[] platformSplits = platformMessageType.split(StrUtil.UNDERLINE);
platform = platformSplits[0];
//存在下划线说明指定了消息类型
if (platformSplits.length >
1) {
messageType = platformSplits[1];
}
DataSourceEnum dataSourceEnum = DataSourceEnum.getByDescribe(platform);
if (dataSourceEnum != null &&
StrUtil.isEmpty(dataSource)) {
dataSource = dataSourceEnum.getDataType();
}
final String dataType = platform;
R response;
Optional<
IMessageHandleService> first = messageHandleServiceMap.values().stream().filter(data -> data.support(dataType)).findFirst();
if (first.isPresent()) {
response = first.get().handleMessage(object, dataSource, messageType);
} else {
log.error("{}类型消息不存在适配器,走默认处理", type);
response = defaultMessageHandleService.handleMessage(object, dataSource, messageType);
}
if (response != null) {
return response.getData();
}
} catch (QiyException e) {
return R.failed(e.getiErrorCode().getI18nMessage());
} catch (Exception e) {
log.error("消息处理有误", e);
return R.failed();
}
return R.ok();
}
public IMessageHandleService getDefaultMessageHandleService() {
return defaultMessageHandleService;
}
public String getIpAddress(){
HttpServletRequest request = RequestUtil.getRequest();
String ipAddress = IpHelperUtils.getIpAddr(request);
String ip = StrUtil.trim(ipAddress).replace(" ","");
if (ip.contains(IP_UTILS_FLAG)){
String[] split = ip.split(StrUtil.COMMA);
for (int i = 0; i < split.length; i++) {
boolean b = IpHelperUtils.internalIp(split[i]);
if (!b){
ip = split[i];
}
}
}
return ip;
}
}

默认消息处理

IMessageHandleService.java

public interface IMessageHandleService {
/**
* 是否适配
* @param type
*/
Boolean support(String type);
/**
* 处理消息
* @param object
* @param dataSource
*/
R handleMessage(Object object, String dataSource, String type) throws Exception;
}

业务处理适配器

QiyModelAssembleService.java

public interface QiyModelAssembleService {
Object assembleModel(Object object, String dataSource);
}

事件处理器1

QiyMessageHandleService.java

/**
* @author kele
* @description
*/
@Component
@AllArgsConstructor
@Slf4j
public class QiyMessageHandleService
implements IMessageHandleService {
private final KafkaSender kafkaSender;
@Override
public Boolean support(String type) {
return DataSourceEnum.AIO_CLOUD.getDescribe().equals(type);
}
@Override
public R handleMessage(Object object, String dataSource, String type) {
SyncRequestBody syncRequestBody = JSON.parseObject(JSON.toJSONString(object), SyncRequestBody.class)
;
DataUploadType dataUploadType = DataUploadType.valueOf(syncRequestBody.getType());
JSONObject data = syncRequestBody.getData();
if(DataSourceEnum.P8000.getDescribe().equals(dataSource)){
data.put("dataSource",DataSourceEnum.P8000.getDataType());
}
String topic = "";
switch (dataUploadType) {
case DEVICE_UPDATE:
case DEVICE_DELETE:
case DEVICE_ADD:
topic = CkafkaTopicEnum.DEVICE_CHANGE.getTopic();
break;
case PROP:
topic = CkafkaTopicEnum.DEVICE_ATTR.getTopic();
nvrConfirmMessage(syncRequestBody);
break;
case EVENT:
topic = CkafkaTopicEnum.ALARM.getTopic();
break;
case FAULT:
topic = CkafkaTopicEnum.FAULT.getTopic();
break;
case STATUS:
topic = CkafkaTopicEnum.DEVICE_STATUS.getTopic();
break;
case EVENT_RECORD:
topic = CkafkaTopicEnum.EVENT_RECORD.getTopic();
break;
}
log.info("qiyiCloud 发送消息, topic:{}, data:{}", topic, JSONUtil.toJsonStr(data));
kafkaSender.send(topic, data);
return null;
}
private void nvrConfirmMessage(SyncRequestBody syncRequestBody) {
JSONObject data = syncRequestBody.getData();
QiyRequestMessageData qiyiRequestMessageData = data.toJavaObject(QiyRequestMessageData.class)
;
if (qiyiRequestMessageData != null &&
CollectionUtil.isNotEmpty(qiyiRequestMessageData.getParams())) {
Map<
String, Object> params = qiyiRequestMessageData.getParams();
if (params.containsKey(QiyCloudIdentifierEnum.IO_ALARM_EVENT_UPLOAD.getIdentifier())) {
String handleStatus = params.get(QiyCloudIdentifierEnum.IO_ALARM_EVENT_UPLOAD.getIdentifier()).toString();
JSONObject result = new JSONObject();
result.put("deviceId", qiyiRequestMessageData.getDevId());
result.put("handleStatus", handleStatus);
result.put("time", qiyiRequestMessageData.getTime() / 1000);
result.put("remark", QiyCloudIdentifierEnum.IO_ALARM_EVENT_UPLOAD.getIdentifier());
log.info("发送NVR信号量告警事件:{}", JSONUtil.toJsonStr(result));
kafkaSender.send(CkafkaTopicEnum.CONFIRM.getTopic(), result);
}
}
}
}

事件处理器2

ChengQunMessageHandleService.java

/**
* @author: kele2
* @since: 2024/8/19 19:22
* @description: 拾音器设备
*/
@Component
@AllArgsConstructor
@Slf4j
public class ChengQunMessageHandleService
implements IMessageHandleService {
@Override
public Boolean support(String type) {
return DataSourceEnum.CHENG_QUN.getDescribe().equals(type);
}
@Override
public R handleMessage(Object object, String dataSource, String msgType) throws Exception {
String message;
if (object instanceof String) {
message = (String) object;
} else {
message = JSON.toJSONString(object);
}
//JSONObject jsonObject = (JSONObject) JSONObject.toJSON(object);
//String msgType = jsonObject.getString("msgType");
ChengQunMsgTypeEnum typeEnum = ChengQunMsgTypeEnum.getByMsgType(msgType);
if (ChengQunMsgTypeEnum.DEFAULT != typeEnum) {
QiyModelAssembleService qiyiModelAssembleService = (QiyModelAssembleService) SpringUtil.getBean(typeEnum.getHandlerClazz());
qiyiModelAssembleService.assembleModel(message, dataSource);
} else {
log.error("{}平台 类型{}暂未配置对应的数据组装服务!", dataSource, msgType);
}
return null;
}
}

业务处理实现

1、设备告警

ChengQunAlarmMessageHandler.java

/**
* @author: kele2
* @since: 2024/8/19 19:22
* @description: CHENG_QUN
*/
@Slf4j
@Component
public class ChengQunAlarmMessageHandler
implements QiyModelAssembleService {
@Autowired
private KafkaSender kafkaSender;
@Override
public Object assembleModel(Object object, String dataSource) {
String message;
if (object instanceof String) {
message = (String) object;
} else {
message = JSON.toJSONString(object);
}
ChengQunAlarmMessageDTO alarmMessageDTO = JSON.parseObject(message, ChengQunAlarmMessageDTO.class)
;
if (alarmMessageDTO == null || alarmMessageDTO.getAudio() == null){
log.error("橙群 设备告警消息格式错误:{}", message);
return R.ok();
}
ChengQunAlarmMessage alarmMessage = new ChengQunAlarmMessage(alarmMessageDTO);
log.info("橙群 设备告警发送消息, 设备id:{}, 告警类型:{}", alarmMessage.getDeviceId(), alarmMessage.getAlarmType());
kafkaSender.send(CkafkaTopicEnum.ALARM.getTopic(), alarmMessage);
return R.ok();
}
}
2、设备状态

ChengQunDeviceStatusServiceImpl.java

/**
* @author: kele2
* @since: 2024/8/26 14:58
* @description:
*/
@Slf4j
@Service
public class ChengQunDeviceStatusServiceImpl
implements ChengQunDeviceStatusService{
@Autowired
private KafkaSender kafkaSender;
@Override
public void deviceOfflineMessage(String deviceId) {
ChengQunHearbeatMessageDTO hearbeatMessageDTO = new ChengQunHearbeatMessageDTO();
hearbeatMessageDTO.setImei(deviceId);
hearbeatMessageDTO.setBeat_time( System.currentTimeMillis() / 1000);
hearbeatMessageDTO.setStatus(ChengQunConstants.DEVICE_OFFLINE);
ChengQunHearbeatMessage hearbeatMessage = new ChengQunHearbeatMessage(hearbeatMessageDTO);
log.info("橙群 设备离线发送消息, 设备信息:{}", JSONUtil.toJsonStr(hearbeatMessage));
kafkaSender.send(CkafkaTopicEnum.DEVICE_STATUS.getTopic(), hearbeatMessage);
ChengQunAlarmMessageDTO alarmMessageDTO = new ChengQunAlarmMessageDTO();
alarmMessageDTO.setSn(deviceId);
alarmMessageDTO.setTs(System.currentTimeMillis() / 1000);
ChengQunAlarmMessage alarmMessage = new ChengQunAlarmMessage(alarmMessageDTO);
alarmMessage.setAlarmType(ChengQunConstants.AUDIO_OFFLINE_FAULT);
log.info("橙群 设备离线故障消息, 设备信息:{}", JSONUtil.toJsonStr(hearbeatMessage));
kafkaSender.send(CkafkaTopicEnum.FAULT.getTopic(), alarmMessage);
}
}

优点

  • 可以让任何两个没有关联的类一起运行
  • 提高了类的复用性
  • 增加了类的透明度
  • 灵活性好

缺点

适配器模式是Java中非常常用的设计模式,特别是在需要整合第三方库或遗留代码时非常有用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/917052.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网站建设法规政策高密建网站

正题 比赛链接:https://ac.nowcoder.com/acm/contest/1084#question 成绩 T1:T1:T1:数数 题目大意 给出nnn&#xff0c;求∑i1n∑j1n(i∗j)\sum_{i1}^n \sum_{j1}^n (i*j)i1∑n​j1∑n​(i∗j) 和 ∏i1n∏j1n(i∗j)\prod_{i1}^n\prod_{j1}^n(i*j)i1∏n​j1∏n​(i∗j) 解题…

欧拉函数学习笔记

欧拉函数学习笔记1.定义 先讲一下欧拉函数的定义:欧拉函数 \(\phi(n)\) 定义为不超过 \(n\) 且与 \(n\) 互质的正整数的个数。 \(\phi(n)=\sum_{i=1}^{n}[\gcd(i,n)=1]\) 例子:n = 8:小于 \(n\) 的正整数是 [1, 2, …

PDF论文文字公式提取,翻译与对照代码(自用)

代码1: import redef process_markdown_file(input_file, output_file):# 步骤1: 读取文件并存储为[正文,标签]格式的列表lines = []with open(input_file, r, encoding=utf-8) as f:for line in f:content = line.rst…

福州网站建设招聘信息国外作品集网站

气压计LPS25HB开发----1.轮询获取气压计数据 概述视频教学样品申请源码下载产品特性通信模式速率生成STM32CUBEMX串口配置IIC配置SA0地址设置串口重定向参考程序SA0设置模块地址获取ID复位操作BDU设置设置速率轮询读取数据演示 概述 本文将介绍如何使用 LPS25HB 传感器来读取数…

华为鸿蒙 ArkTS 实战:基于 RelationalStore 的 SQLite 实现本地数据持久化 - 实践

华为鸿蒙 ArkTS 实战:基于 RelationalStore 的 SQLite 实现本地数据持久化 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; fon…

ABAP 调用HTTP上传附件中文乱码

问题: ABAP 使用form-data格式,调用HTTP上传文件,文件名中的中文出现乱码 解决: 使用 escape 函数对文件名进行正确的编码转换DATA(lv_encoded_filename) = escape( val = iv_filenameformat = cl_abap_for…

淘宝天猫优惠卷网站建设高端购物网站建设

正则表达式&#xff0c;又称正规表示法、常规表示法&#xff08;Regular Expression&#xff0c;在代码中常简写为regex、regexp或RE&#xff09;&#xff0c;是计算机科学中的一个概念。正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器…

安徽省建设工程信息网站中国外贸网

W...Y的主页&#x1f60a; 代码仓库分享&#x1f495; ​ &#x1f354;前言&#xff1a; 今天我们正式进入C篇章&#xff0c;作为学过C语言的同志&#xff0c;继续学习C肯定就不会进行那些与C语言相同的学习&#xff0c;因为C语言的内容在C中也可以正常使用&#xff0c;所…

PDF入参以及模板对应签章图踩坑点 JAR版本为 iText5

模板PDF推荐使用万兴PDF工具破解版调整表单域和表单域名称,入参后的PDF需要设置入参字体和扁平化来保证PDF可以直接显示入参参数。可以防止出现打开PDF显示文本域// OSS上的PDF模板文件URLprivate static final Strin…

从 0 到 1 精通 SkyWalking:分布式系统的 “透视镜“ 技巧全解析

从 0 到 1 精通 SkyWalking:分布式系统的 “透视镜“ 技巧全解析pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "…

系统调用brk 和 mmap 有什么不同?

系统调用brk 和 mmap 有什么不同?1. 核心功能差异 ‌brk‌: 通过调整进程堆顶指针(_edata)扩展/收缩堆空间,仅适用于连续内存分配‌。 ‌mmap‌:在进程虚拟地址空间中创建独立映射区域,支持文件/匿名内存映射,…

雷达系统杂波设计与仿真

一、杂波建模方法体系 1. 统计建模方法瑞利分布:适用于低分辨率雷达地杂波,假设散射体数量足够多且无主导散射体 % 瑞利分布仿真代码 sigma = 1.2; % 杂波标准差 clutter = sigma * abs(randn(1,1000));韦布尔分布:…

把网站做成微信小程序网页设计作业设计意图

[css] 异步加载CSS的方式有哪些&#xff1f; 异步加载CSS 说到加载 CSS 这种事儿不是很简单吗&#xff1f;像这样咯&#xff1a; 这不就完事儿了嘛&#xff01; 这样是没错&#xff01;但是这样有问题啊——会阻塞渲染&#xff01;浏览器看到这个标签就会停下手里的活儿&…

国标GB28181视频平台EasyCVR一体化加油站安防视频监控方案与实践

国标GB28181视频平台EasyCVR一体化加油站安防视频监控方案与实践在现代油品销售行业,确保加油站的安全运营和提供优质的客户服务是至关重要的。为了满足这些需求,必须构建一个依托于尖端信息技术的视频监控系统。这一…

JavaScript 沙箱

概述 沙箱可以简单的理解为一个虚拟机,是一个和宿主机隔离的环境,在这个环境中去运行一些不受信任的代码或者应用程序,防止不安全的代码对系统造成损害。 比如我们现在知道某个应用是诈骗软件或者病毒软件,但是我们…

PDF入参以及模板对应签章图踩坑点

模板PDF推荐使用万兴PDF工具破解版调整表单域和表单域名称,入参后的PDF需要设置入参字体和扁平化来保证PDF可以直接显示入参参数。可以防止出现打开PDF显示文本域// OSS上的PDF模板文件URLprivate static final Strin…

网站分页导航廊坊百度快照优化

一、Android抓包方式 对Https降级进行抓包&#xff0c;降级成Http使用抓包工具对Https进行抓包 二、常用的抓包工具 wireshark&#xff1a;侧重于TCP、UDP传输层&#xff0c;HTTP/HTTPS也能抓包&#xff0c;但不能解密HTTPS报文。比较复杂fiddler&#xff1a;支持HTTP/HTTPS…

高性能PCIe 3.0软核,x1~x16,支持EP/RC,AXI4接口,内置DMA控制器,适用ASIC和FPGA

PCIe-AXI-Controller兼容PCI Express Base Specification Revision 3.1,实现PCIe PHY Layer,Data Link Layer以及Transaction Layer的所有功能特性,不仅内置DMA控制器,而且具备AXI4用户接口,提供一个高性能,易于…

使用git clone 批量下载huggingface模型文件

1.选定要下载的模型 以下载moka-ai/m3e-base为例,切换到Files and versions。2.更改下载网页的url 如上图所示,当前要下载模型网页的url为: https://huggingface.co/moka-ai/m3e-base/tree/mainAI写代…

深入 Spring Boot 异常处理底层机制 - 指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …