初学 Java 设计模式(十七):实战中介者模式 「菜鸟驿站」

期权梦想家
• 阅读 1390

一、中介者模式介绍

1. 解决的问题

主要解决当对象与对象之间存在大量关联关系时,若一个对象发生改变,要跟踪与之相关的对象,同时做出相应处理的问题。

2. 定义

中介者模式是一种行为设计模式,能减少对象之间混乱无序的依赖关系。该模式会限制对象之间的直接交互,迫使它们通过一个中介者对象进行合作。

3. 应用场景

  • 当一些对象与其他对象紧密耦合以至于难以对其进行修改时,可使用中介者模式。
  • 当组件因过于依赖其他组件而无法在不同应用中复用时,可使用中介者模式。
  • 为了在不同情景下复用一些基本行为,导致需要被迫创建大量组件子类时,可使用终结者模式。

二、中介者模式优缺点

1. 优点

  • 单一职责原则:可以将多个组件间的交流抽取到同一位置,使其更易于理解和维护。
  • 开闭原则:无需修改实际组件就能增加新的中介者。
  • 可以减轻应用中多个组件的耦合情况。
  • 可以更方便地复用各个组件。

2. 缺点

  • 一段时间后,中介者可能会演化为上帝对象。

三、中介者模式应用实例:菜鸟驿站

1. 实例场景

相信大家平时快递来不及拿的话,大部分时候都会选择让快递小哥将快递放到菜鸟驿站,我们在放学/下班后再去菜鸟驿站拿自己的快递。同时,我们如果有快递需要寄出,也是现在菜鸟驿站填写寄件单,然后快递小哥从菜鸟驿站拿到快递,发货。

其实在这里,菜鸟驿站就是一个中介者,承担着快递小哥和我们之间的重要交流枢纽。

今天,我们就以菜鸟驿站为例,介绍一下中介者模式。

2. 中介者模式实现

2.1 工程结构
mediator-pattern
└─ src
    ├─ main
    │    └─ java
    │    └─ org.design.pattern.mediator
    │       ├─ model
    │       │    ├─ ExpressPackage.java
    │       │    ├─ Courier.java
    │       │    └─ User.java
    │       └─ service
    │            ├─ CourierStation.java
    │            └─ impl
    │                 └─ CaiNiaoCourierStation.java
    └─ test
        └─ java
            └─ org.design.pattern.mediator
                  └─ CourierStationTest.java
2.2 代码实现
2.2.1 实体类

快递包裹

/**
 * 快递包裹
 */
@Getter
@Setter
@AllArgsConstructor
public class ExpressPackage {

    /**
     * 包裹id
     */
    private String id;

    /**
     * 包裹名称
     */
    private String name;

    /**
     * 收件人电话
     */
    private String consigneePhoneNumber;

    /**
     * 发件快递站
     */
    private CourierStation sendCourierStation;

    /**
     * 收件快递站
     */
    private CourierStation receiveCourierStation;
}

快递员

/**
 * 快递员
 */
@Slf4j
@Getter
@Setter
@AllArgsConstructor
public class Courier {

    /**
     * 快递员id
     */
    private String id;

    /**
     * 快递员姓名
     */
    private String name;

    /***
     * 送快递(放到快递站)
     *
     * @param expressPackage 快递包裹
     */
    public void sendExpressPackage(ExpressPackage expressPackage) {
        expressPackage.getReceiveCourierStation().receiveExpressPackage(expressPackage);
    }

    /**
     * 收快递(从快递站取件,并发货)
     *
     * @param expressPackage 快递包裹
     */
    public void receiveExpressPackage(ExpressPackage expressPackage) {
        log.info(
            "The courier {} has arrived in the hands of the express package {}, and it will be sent to you immediately.",
            this.getName(),
            expressPackage.getName()
        );
    }
}

用户

/**
 * 用户
 */
@Getter
@Setter
@AllArgsConstructor
public class User {

    /**
     * 用户id
     */
    private String id;

    /**
     * 用户姓名
     */
    private String name;

    /**
     * 用户电话
     */
    private String phone;

    /**
     * 寄快递(快递放到快递站)
     *
     * @param expressPackage 快递包裹
     */
    public void sendExpressPackage(ExpressPackage expressPackage) {
        expressPackage.getSendCourierStation().sendExpressPackage(expressPackage);
    }
}
2.2.2 服务类

快递站中介者

/**
 * 快递站
 */
public interface CourierStation {

    /**
     * 收件服务
     *
     * @param expressPackage 快递包裹
     */
    void receiveExpressPackage(ExpressPackage expressPackage);

    /**
     * 寄件服务
     *
     * @param expressPackage 快递包裹
     */
    void sendExpressPackage(ExpressPackage expressPackage);
}

菜鸟驿站

/**
 * 菜鸟驿站
 */
@Slf4j
@Getter
@Setter
public class CaiNiaoCourierStation implements org.design.pattern.mediator.service.CourierStation {

    /**
     * 快递员列表
     */
    private List<Courier> courierList;

    /**
     * 收件服务
     *
     * @param expressPackage 快递包裹
     */
    @Override
    public void receiveExpressPackage(ExpressPackage expressPackage) {
        log.info(
            "The package {} has arrived at the cai niao courier station, please pick it up as soon as possible.",
            expressPackage.getName()
        );
    }

    /**
     * 寄件服务
     *
     * @param expressPackage 快递包裹
     */
    @Override
    public void sendExpressPackage(ExpressPackage expressPackage) {
      Optional<Courier> courierOptional = courierList.stream().findAny();
      if (courierOptional.isPresent()) {
          Courier courier = courierOptional.get();
          courier.receiveExpressPackage(expressPackage);
      }
    }
}
2.3 测试验证
2.3.1 测试验证类
/**
 * 快递站测试类
 */
public class CourierStationTest {

    @Test
    public void testReceiveExpressPackage() {
        Courier courier = new Courier("1", "快递小哥");
        CaiNiaoCourierStation courierStation = new CaiNiaoCourierStation();
        courierStation.setCourierList(Collections.singletonList(courier));
        ExpressPackage expressPackage = new ExpressPackage(
                "1", "PS5", "13245678910", null, courierStation
        );
        courier.sendExpressPackage(expressPackage);
    }

    @Test
    public void testSendExpressPackage() {
        User user = new User("1", "张三", "13245678910");
        Courier courier = new Courier("1", "快递小哥");
        CaiNiaoCourierStation courierStation = new CaiNiaoCourierStation();
        courierStation.setCourierList(Collections.singletonList(courier));
        ExpressPackage expressPackage = new ExpressPackage(
                "1", "Kindle", "13245678910", courierStation, null
        );
        user.sendExpressPackage(expressPackage);
    }
}
2.3.2 测试结果
22:19:52.811 [main] INFO  o.d.p.m.s.impl.CaiNiaoCourierStation - The package PS5 has arrived at the cai niao courier station, please pick it up as soon as possible.
22:19:52.814 [main] INFO  o.d.pattern.mediator.model.Courier - The courier 快递小哥 has arrived in the hands of the express package Kindle, and it will be sent to you immediately.

Process finished with exit code 0

四、中介者模式结构

初学 Java 设计模式(十七):实战中介者模式 「菜鸟驿站」

  1. 组件(Component)是包含各种业务逻辑的类。每个组件都有一个指向中介者的引用,该引用被声明为中介者接口类型。组件不知道中介者实际所属的类,因此可通过连接到不同的中介者使其能在其他程序中复用。
  2. 中介者(Mediator)接口声明了与组件交流的方法,但通常仅包含一个通知方法。组件可将任意上下文(包括自身对象)作为该方法的参数,只有这样接收组件和发送者类才不会耦合。
  3. 具体中介者(Concrete Mediator)封装了多种组件间的关系。具体中介者通常会保存所有组件的引用并对其进行管理,甚至有时会对其生命周期进行管理。
  4. 组件并不知道其他组件的情况。如果组件内发生了重要事件,它只能通知中介者。中介者收到通知后能轻易确定发送者,这就足以判断下一步要触发的组件。

    对于组件来说,中介者看上去完全就是一个黑箱。发送者不知道最终会由谁来处理自身的请求,接收者也不知道请求究竟来自于谁。

设计模式并不难学,其本身就是多年经验提炼出的开发指导思想,关键在于多加练习,带着使用设计模式的思想去优化代码,就能构建出更合理的代码。

源码地址:https://github.com/yiyufxst/design-pattern-java

参考资料:
小博哥重学设计模式:https://github.com/fuzhengwei/itstack-demo-design
深入设计模式:https://refactoringguru.cn/design-patterns/catalog

点赞
收藏
评论区
推荐文章
观察者模式在spring中的应用
作者:王子源1观察者模式简介1.1定义指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布订阅模式、模型视图模式,它是对象行为型模式。
Wesley13 Wesley13
3年前
java中的23种设计模式
java中一共23种设计模式!按照目的来分,设计模式可以分为创建型模式、结构型模式和行为型模式。创建型模式用来处理对象的创建过程;结构型模式用来处理类或者对象的组合;行为型模式用来对类或对象怎样交互和怎样分配职责进行描述。创建型模式用来处理对象的创建过程,主要包含以下5种设计模式:工厂方法模
Stella981 Stella981
3年前
Apache commons chain 初探
Apachecommonschain是什么Apachecommonchain是对责任链设计模式的改造封装,让使用者更加方便的使用。简单回顾一下责任链设计模式在阎宏博士的《JAVA与模式》一书中开头是这样描述责任链(ChainofResponsibility)模式的:责任链模式是一种对象的行为模式。在
Stella981 Stella981
3年前
Javascript中创建函数的几种方法
//工厂函数模式//无法解决对象识别问题functionperson0(name,age,job){varobjnewObject();obj.namename;obj.ageage;obj.jobjob;returno
Wesley13 Wesley13
3年前
Java设计模式之责任链模式
引入责任链模式责任链模式顾名思义,责任链模式(ChainofResponsibilityPattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会
Wesley13 Wesley13
3年前
Java中jdk代理和cglib代理
代理模式给某一个对象提供一个代理,并由代理对象控制对原对象的引用。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。在Java中代理模式从实现方式上可以分为两个类别:静态代理和动态代理静态代理:也就是我们学习设计模式之代理模式时常见的事例,具体不在赘述,参见:
Stella981 Stella981
3年前
MediatorPattern中介者模式
中介者模式1.定义使用一个中介对象封装一系列的对象交互,中介者使用对象不需要显式的相互作用,从而实降现低耦合度,且可以独立改变被封装的一些列对象之间的交互。中介者模式也叫做调停者模式:对象之间的依赖就像战争,很混乱,加入一个中心,所有对象都和中心交流,接受中心的调停处理。中介者模式通常有4个角色Abstrac
Wesley13 Wesley13
3年前
22. 状态模式
在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的context对象。介绍意图:允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。主要解决:对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。何时使用:代码中包含大量与对象状态有关的条件语句
Wesley13 Wesley13
3年前
23种设计模式(面向对象语言)
一、设计模式的分类总体来说设计模式分为三大类:创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。创建型模式是用来创建对象的模式,抽象了实例化的过程,帮助一个系统独立于其他关联对象的创建、组合和表示方式。所有的创建型模式都有两个主要功能:  1.将系统所使用的具体类的信息封装起来  2.隐藏
Wesley13 Wesley13
3年前
C++ 常用设计模式(学习笔记)
设计模式1、工厂模式在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。工厂模式作为一种创建模式,一般在创建复杂对象时,考虑使用;在创建简单对象时,建议直接new完成一个实例对象的创建。1.1、简单工厂模式主要特点是需要在工厂类中做判断,从而创造相应的产品,当
设计模式-单例模式概述 | 京东云技术团队
我们常把23种经典的设计模式分为三类:创建型、结构型、行为型,其中创建型设计模式主要解决“对象的创建”问题,将创建和使用代码解耦,结构型设计模式主要解决“类或对象的组合或组装”问题,将不同功能代码解耦,行为型设计模式主要解决“类或对象之间的交互”问题,将不