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
示例场景
假设我们有一个旧的媒体播放器只能播放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不支持多重继承,所以类适配器有一定局限性
适配器模式是Java中非常常用的设计模式,特别是在需要整合第三方库或遗留代码时非常有用。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/917052.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!相关文章
网站建设法规政策高密建网站
正题
比赛链接:https://ac.nowcoder.com/acm/contest/1084#question 成绩 T1:T1:T1:数数
题目大意
给出nnn,求∑i1n∑j1n(i∗j)\sum_{i1}^n \sum_{j1}^n (i*j)i1∑nj1∑n(i∗j) 和 ∏i1n∏j1n(i∗j)\prod_{i1}^n\prod_{j1}^n(i*j)i1∏nj1∏n(i∗j)
解题…
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…
淘宝天猫优惠卷网站建设高端购物网站建设
正则表达式,又称正规表示法、常规表示法(Regular Expression,在代码中常简写为regex、regexp或RE),是计算机科学中的一个概念。正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器…
安徽省建设工程信息网站中国外贸网
W...Y的主页😊
代码仓库分享💕
🍔前言:
今天我们正式进入C篇章,作为学过C语言的同志,继续学习C肯定就不会进行那些与C语言相同的学习,因为C语言的内容在C中也可以正常使用,所…
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的方式有哪些?
异步加载CSS 说到加载 CSS 这种事儿不是很简单吗?像这样咯: 这不就完事儿了嘛!
这样是没错!但是这样有问题啊——会阻塞渲染!浏览器看到这个标签就会停下手里的活儿&…
国标GB28181视频平台EasyCVR一体化加油站安防视频监控方案与实践
国标GB28181视频平台EasyCVR一体化加油站安防视频监控方案与实践在现代油品销售行业,确保加油站的安全运营和提供优质的客户服务是至关重要的。为了满足这些需求,必须构建一个依托于尖端信息技术的视频监控系统。这一…
JavaScript 沙箱
概述
沙箱可以简单的理解为一个虚拟机,是一个和宿主机隔离的环境,在这个环境中去运行一些不受信任的代码或者应用程序,防止不安全的代码对系统造成损害。
比如我们现在知道某个应用是诈骗软件或者病毒软件,但是我们…
PDF入参以及模板对应签章图踩坑点
模板PDF推荐使用万兴PDF工具破解版调整表单域和表单域名称,入参后的PDF需要设置入参字体和扁平化来保证PDF可以直接显示入参参数。可以防止出现打开PDF显示文本域// OSS上的PDF模板文件URLprivate static final Strin…
网站分页导航廊坊百度快照优化
一、Android抓包方式
对Https降级进行抓包,降级成Http使用抓包工具对Https进行抓包
二、常用的抓包工具
wireshark:侧重于TCP、UDP传输层,HTTP/HTTPS也能抓包,但不能解密HTTPS报文。比较复杂fiddler:支持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", …