一、适配器模式介绍

1. 解决的问题

次要解决在零碎中,将一些现存对象放入新环境中,而新环境要求的接口和现存对象不匹配的问题。

2. 定义

适配器模式是一种结构型设计模式,它能使接口不兼容的对象可能相互合作。

3. 利用场景

  • 心愿应用某个类,但其接口与其余代码不兼容时,能够应用适配器类。
  • 如果须要复用这样一些类,它们处于同一个继承体系,并且又有了额定的一些独特的办法,然而这些独特的办法不是这一继承体系中所有子类具备的共性。

二、适配器模式优缺点

1. 长处

  • 繁多职责准则:能够将接口或数据转换代码从程序次要业务逻辑中拆散。
  • 开闭准则:只有客户端代码通过客户端接口与适配器进行交互,就能在不批改现有客户端代码的状况下,在程序中增加新类型的适配器。

2. 毛病

  • 代码整体复杂度减少:因为须要减少一系列接口和类,有时间接更改服务类来保障兼容可能更简略。

三、适配器模式利用实例:同步监控告诉至工作群

1. 实例场景

为了更好地感知零碎的运行状况,咱们会在零碎运行的各个链路埋下监控点,出现异常就会进行邮件告诉。 那么问题来了,在咱们沉迷在代码的世界里时,有时会疏忽一些邮件告诉,通过一系列团队外部探讨,决定将异样监控告诉同步发送到咱们的工作群(钉钉、微信)里,这样就能相互揭示。

工作群的音讯告诉须要一些鉴权等机制后能力调用告诉服务,和之前零碎接入的邮件告诉模式齐全不统一,这时,就能够用适配器模式,将工作群的告诉封装后适配到监控零碎的告诉接口上。

2. 适配器模式实现

2.1 工程构造
adapter-pattern└─ src    ├─ main    │    └─ java    │    └─ org.design.pattern.adapter    │       ├─ model    │       │  ├─ DingDingApi.java    │       │  └─ MonitorMessage.java    │       └─ service    │          ├─ NotificationService.java    │          └─ impl    │              ├─ EmailNotificationServiceImpl.java    │              └─ DingDingNotificationServiceImpl.java    └─ test        └─ java            └─ org.design.pattern.adapter.test                  └─ NotificationTest.java
2.2 代码构造
2.2.1 根底类

监控音讯类

/** * 监控音讯 */@Getter@Setter@AllArgsConstructorpublic class MonitorMessage {    /**     * 题目     */    private String title;    /**     * 音讯     */    private String message;}

钉钉 Api 类

/** * 钉钉Api类 */public class DingDingApi {    private final Logger log = LoggerFactory.getLogger(DingDingApi.class);    private String $loginApi;    private String $apiKey;    public DingDingApi(String $loginApi, String $apiKey) {        this.$loginApi = $loginApi;        this.$apiKey = $apiKey;    }    /**     * 登录     */    public void logIn() {        log.info("登录钉钉账户胜利");    }    /**     *     * @param message     * @param charId     * @return     */    public boolean sendMessage(String message, String charId) {        boolean result = false;        try {            result = true;            log.info("发送钉钉音讯告诉到群{}胜利:{}", charId, message);        } catch (Exception e) {            log.error("发送钉钉告诉失败:", e);        }        return result;    }}
2.2.2 服务类

告诉服务接口

/** * 告诉服务接口 */public interface NotificationService {    void send(MonitorMessage monitorMessage);}

邮件告诉服务实现类

/** * 邮件告诉服务实现类 */public class EmailNotificationServiceImpl implements NotificationService {    private final Logger log = LoggerFactory.getLogger(EmailNotificationServiceImpl.class);    @Override    public void send(MonitorMessage monitorMessage) {        boolean sendResponse = mail(monitorMessage);        if (sendResponse) {            log.info("{} message send email success", monitorMessage.getTitle());        } else {            log.error("{} message send email failed", monitorMessage.getTitle());        }    }    /**     * 发送邮件     * @param monitorMessage     * @return     */    private boolean mail(MonitorMessage monitorMessage) {        boolean result = true;        // 发送邮件...        return result;    }}

钉钉告诉服务实现类

/** * 钉钉告诉服务实现类 */public class DingDingNotificationServiceImpl implements NotificationService {    private final Logger log = LoggerFactory.getLogger(DingDingNotificationServiceImpl.class);    /**     * 钉钉Api     */    private DingDingApi dingDingApi;    /**     * 工作群id     */    private String chatId;    public DingDingNotificationServiceImpl(DingDingApi dingDingApi, String chatId) {        this.dingDingApi = dingDingApi;        this.chatId = chatId;    }    @Override    public void send(MonitorMessage monitorMessage) {        this.dingDingApi.logIn();;        boolean sendResponse = this.dingDingApi.sendMessage(monitorMessage.getMessage(), this.chatId);        if (sendResponse) {            log.info("{} send to chartId {} success", monitorMessage.getTitle(), this.chatId);        } else {            log.error("{} send to chartId {} failed", monitorMessage.getTitle(), this.chatId);        }    }}
2.3 测试验证
2.3.1 测试验证类
/** * 告诉测试类 */public class NotificationTest {    @Test    public void testNotification() {        MonitorMessage monitorMessage = new MonitorMessage("获取mongo数据失败", "错误信息:xxx");        //邮件告诉        NotificationService emailNotificationService = new EmailNotificationServiceImpl();        emailNotificationService.send(monitorMessage);        //钉钉告诉        DingDingApi dingDingApi = new DingDingApi("https://www.dingtalk.com/", "xxx");        NotificationService dingDingNotificationService = new DingDingNotificationServiceImpl(dingDingApi, "1");        dingDingNotificationService.send(monitorMessage);    }}
2.3.2 测试后果
16:02:22.892 [main] INFO  o.d.p.a.s.i.EmailNotificationServiceImpl - 获取mongo数据失败 message send email success16:02:22.894 [main] INFO  o.d.p.adapter.model.DingDingApi - 登录钉钉账户胜利16:02:22.894 [main] INFO  o.d.p.adapter.model.DingDingApi - 发送钉钉音讯告诉到群1胜利:错误信息:xxx16:02:22.894 [main] INFO  o.d.p.a.s.i.DingDingNotificationServiceImpl - 获取mongo数据失败 send to chartId 1 successProcess finished with exit code 0

四、适配器模式构造

  1. 客户端(Client)是蕴含以后程序业务逻辑的类。
  2. 客户端服务接口(Client Interface)形容了其余类和客户端代码单干时的协定。
  3. 服务(Service)中存在一些性能类(个别来自第三方或历史代码)。客户端与其接口不兼容,因而无奈间接调用其性能。
  4. 适配器(Adapter)是一个同时和客户端和服务交互的类:在实现客户端接口的同时封装了服务对象。适配器承受客户端通过适配器接口发动的调用,并将其转换为实用于被封装服务对象的调用。
  5. 客户端代码仅需通过接口与适配器交互即可,无需与具体的适配器类耦合。

设计模式并不难学,其自身就是多年教训提炼出的开发指导思想,关键在于多加练习,带着应用设计模式的思维去优化代码,就能构建出更正当的代码。

源码地址:https://github.com/yiyufxst/d...

参考资料:
小博哥重学设计模式:https://github.com/fuzhengwei...
深刻设计模式:https://refactoringguru.cn/de...