type
status
date
slug
summary
tags
category
icon
password
一、定义

适配器模式:将一个类的接口适配成用户所期待的那样,一个适配允许通常因为接口不兼容的不能在一起工作的类,使其在一起工作,做法是将自己的接口包裹在一个已存在的类中
二、示例:
模拟场景:
例如:1、80,90后应该了解万能充电器,实现对各种规格的电池充电功能,这就是生活中典型的适配器,
例如:2、某些大型的些营销系统,⼤部分常⻅的都是裂变、拉客,例如;你邀请⼀个⽤户开户、或者邀请⼀个⽤户下单,那么平台就会给你返利,多邀多得。同时随着拉新的量越来越多开始设置每⽉下单都会给⾸单奖励,等等,各种营销场景。
那么这个时候做这样⼀个系统就会接收
各种各样
的MQ消息或者接⼝,如果⼀个个的去开发,就会耗费
很⼤的成本,同时对于后期的拓展也有⼀定的难度。此时就会希望有⼀个系统可以配置⼀下就把外部的
MQ接⼊进⾏,这些MQ就像上⾯提到的可能是⼀些注册开户消息、商品下单消息等等。例如:3、大型的商城系统,用户服务模块可能会调用其他第三方的接口。接口的返回参数和名字都不一样,对于用户是否是首单有各种不一样的判断规则。这时我们需要整合一个适配器通用所有规则
传统编码方式
一旦扩充新的类型消息,需要转换字符,扩充修改代码
package com.qf.design.structure.adapter.tradition; import com.alibaba.fastjson.JSON; import com.qf.design.structure.adapter.entity.OrderMq; import com.qf.design.structure.adapter.entity.create_account; import java.util.Date; public class create_accountMqService { /** * 代码冗长,需要每次都定义一个新的类,来处理字段,一旦字段发生改变,代码随着也改变 * @param message */ public void onMessage(String message){ create_account account= JSON.parseObject(message, create_account.class); Date accountDate = account.getAccountDate(); String address = account.getAddress(); String number = account.getNumber(); //处理自己的业务逻辑 OrderMq mq=new OrderMq(); mq.setCreateOrderTime(accountDate); mq.setUid(number); } }
适配器模式
定义统一处理的类,所有的第三方mq消息,最终会转换此格式:
RebateInfo
package com.qf.design.structure.adapter.design; import java.util.Date; public class RebateInfo { /** * 自己定义的统一接受处理的类 */ private String userId; // 用户ID private String bizId; // 业务ID private Date bizTime; // 业务时间 private String desc; // 业务描述 // ... get/set public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getBizId() { return bizId; } public void setBizId(String bizId) { this.bizId = bizId; } public Date getBizTime() { return bizTime; } public void setBizTime(Date bizTime) { this.bizTime = bizTime; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public void setBizTime(String bizTime) { this.bizTime = new Date(Long.parseLong("1591077840669")); } }
定义适配器,适配所有字段,并且转换:
MQAdapter
package com.qf.design.structure.adapter.design; import com.alibaba.fastjson.JSON; import java.lang.reflect.InvocationTargetException; import java.util.Map; import java.util.Set; public class MQAdapter { public static RebateInfo filter(String strJson, Map<String, String> link) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { return filter(JSON.parseObject(strJson, Map.class), link); } public static RebateInfo filter(Map obj, Map<String, String> link) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { RebateInfo rebateInfo = new RebateInfo(); for (String key : link.keySet()) { Object val = obj.get(link.get(key)); RebateInfo.class.getMethod("set" + key.substring(0, 1).toUpperCase() + key.substring(1), String.class).invoke(rebateInfo, val.toString()); } return rebateInfo; } }
测试:
ApiTest
@Test public void mqTest() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, ParseException { SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date parse = s.parse("2020-06-01 23:20:16"); create_account create_account = new create_account(); create_account.setNumber("100001"); create_account.setAddress("河北省.廊坊市.广阳区.大学里职业技术学院"); create_account.setAccountDate(parse); create_account.setDesc("在校开户"); HashMap<String, String> link01 = new HashMap<String, String>(); link01.put("userId", "number"); link01.put("bizId", "number"); link01.put("bizTime", "accountDate"); link01.put("desc", "desc"); RebateInfo rebateInfo01 = MQAdapter.filter(JSON.toJSONString(create_account), link01); System.out.println("mq.create_account(适配前)" + create_account.toString()); System.out.println("mq.create_account(适配后)" + JSON.toJSONString(rebateInfo01)); System.out.println(""); OrderMq orderMq = new OrderMq(); orderMq.setUid("100001"); orderMq.setSku("10928092093111123"); orderMq.setOrderId("100000890193847111"); orderMq.setCreateOrderTime(parse); HashMap<String, String> link02 = new HashMap<String, String>(); link02.put("userId", "uid"); link02.put("bizId", "orderId"); link02.put("bizTime", "createOrderTime"); RebateInfo rebateInfo02 = MQAdapter.filter(JSON.toJSONString(orderMq), link02); System.out.println("mq.orderMq(适配前)" + orderMq.toString()); System.out.println("mq.orderMq(适配后)" + JSON.toJSONString(rebateInfo02)); }
是否为首单的判断,定义统一的规则,抽象接口:
IOrderService
package com.qf.design.structure.adapter.design; public interface IOrderService { boolean isFirst(String uId); }
本地的首单规则修改:
OrderServiceImpl
package com.qf.design.structure.adapter.design; import com.qf.design.structure.adapter.service.OrderService; public class OrderServiceImpl implements IOrderService{ private OrderService orderService=new OrderService(); @Override public boolean isFirst(String uId) { return orderService.queryUserOrderCount(uId)<=1; } }
第三方的首单规则修改:
POPOrderServiceImpl
package com.qf.design.structure.adapter.design; import com.qf.design.structure.adapter.service.POPOrderService; public class POPOrderServiceImpl implements IOrderService{ private POPOrderService popOrderService=new POPOrderService(); @Override public boolean isFirst(String uId) { return popOrderService.isFirstOrder(uId); } }
测试:
ApiTest
@Test public void orderTest(){ IOrderService popOrderAdapterService = new POPOrderServiceImpl(); System.out.println("判断首单,接口适配(POP):" + popOrderAdapterService.isFirst("100001")); IOrderService insideOrderService = new OrderServiceImpl(); System.out.println("判断首单,接口适配(自营):" + insideOrderService.isFirst("100001")); }
UML关系图(适配器模式)
定义一个适配器,统一规则

定义统一规则IOrderService,都去实现此规则:OrderServiceImpl、POPOrderServiceImpl

总结:
从上⽂可以看到不使⽤适配器模式这些功能同样可以实现,但是使⽤了适配器模式就可以让代码:⼲净整洁易于维护、减少⼤量重复的判断和使⽤、让代码更加易于维护和拓展。
尤其是我们对MQ这样的多种消息体中不同属性同类的值,进⾏适配再加上代理类,就可以使⽤简单的配置⽅式接⼊对⽅提供的MQ消息,⽽
不需要⼤量重复
的开发。⾮常利于拓展。- 作者:程序员小舟
- 链接:https://codezhou.top/article/JAVA%E3%80%90%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E3%80%91%E9%80%82%E9%85%8D%E5%99%A8%E6%A8%A1%E5%BC%8F
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章