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

文章目录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);

}

事件处理器1QiyMessageHandleService.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);

}

}

}

}

事件处理器2ChengQunMessageHandleService.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中非常常用的设计模式,特别是在需要整合第三方库或遗留代码时非常有用。

微信相册制作全攻略:从入门到精通
二头身是什么意思