中介者模式(Mediator)

news2024/10/5 16:25:08

中介者模式是一种行为设计模式,可以减少对象之间混乱无序的依赖关系。该模式会限制对象之间的直接交互,迫使它们通过一个封装了对象间交互行为的中介者对象来进行合作,从而使对象间耦合松散,并可独立地改变它们之间的交互。中介者模式又称为调停者模式。

Mediator is a behavior design pattern. It can reduce the disordered dependencies between objects. 
This pattern restricts direct interaction between objects, forcing them to collaborate through a mediator object 
that encapsulates the interaction behavior between objects, resulting in loose coupling between objects 
and the ability to independently change their interactions.  

结构设计

中介者模式包含如下角色:
Component,组件基类,声明组件的基本功能,有一个指向中介者的引用,该引用被声明为中介者接口类型。组件不知道中介者实际所属的类,因此可通过将其连接到不同的中介者以使其能在其他程序中复用。
Mediator,中介者接口,声明了与组件交流的方法,但通常仅包括一个通知方法。组件可将任意上下文作为该方法的参数,只有这样接收组件和发送者类之间才不会耦合。
ConcreteComponent,具体组件,实现组件声明的方法,并自定义业务逻辑接口。
ConcreteMediator,具体中介者,实现中介者接口声明的方法。
中介者模式类图表示如下:
请添加图片描述

伪代码实现

接下来将使用代码介绍下中介者模式的实现。

// 1、中介者接口,声明了与组件交流的方法  
public interface IMediator {
    void notify(Sender sender);
}

//2、具体中介者,实现中介者接口声明的方法
public class ConcreteMediator implements IMediator {
    @Override
    public void notify(Sender sender) {
        String message = sender.getMessage();
        Component target = sender.getTarget();
        target.operation(message);
    }
}

// 3、组件基类,声明组件的基本功能,有一个指向中介者的引用,该引用被声明为中介者接口类型
public abstract class Component {
    protected IMediator mediator;

    public Component(IMediator mediator) {
        this.mediator = mediator;
    }

    public void operation(String message) {
        System.out.println("message is " + message);
    }

    public void send(String message, Component target) {
        Sender sender = new Sender(message, this, target);
        mediator.notify(sender);
    }
}

// 4、具体组件,实现组件声明的方法,并自定义业务逻辑接口
public class ConcreteComponentA extends Component {
    public ConcreteComponentA(IMediator mediator) {
        super(mediator);
    }

    @Override
    public void operation(String message) {
        super.operation(message);
        operationA();
    }

    public void operationA() {
        System.out.println("operationA in a Concrete ComponentA instance");
    }
}
public class ConcreteComponentB extends Component {
    public ConcreteComponentB(IMediator mediator) {
        super(mediator);
    }

    @Override
    public void operation(String message) {
        super.operation(message);
        operationB();
    }

    public void operationB() {
        System.out.println("operationB in a Concrete ComponentB instance");
    }
}
public class ConcreteComponentC extends Component {
    public ConcreteComponentC(IMediator mediator) {
        super(mediator);
    }

    @Override
    public void operation(String message) {
        super.operation(message);
        operationC();
    }

    public void operationC() {
        System.out.println("operationC in a Concrete ComponentC instance");
    }
}
public class ConcreteComponentD extends Component {
    public ConcreteComponentD(IMediator mediator) {
        super(mediator);
    }

    @Override
    public void operation(String message) {
        super.operation(message);
        operationD();
    }

    public void operationD() {
        System.out.println("operationD in a Concrete ComponentD instance");
    }
}

// 5、客户端
public class MediatorClient {
    public void test() {
        IMediator mediator = new ConcreteMediator();
        Component componentA = new ConcreteComponentA(mediator);
        Component componentB = new ConcreteComponentB(mediator);
        Component componentC = new ConcreteComponentC(mediator);
        Component componentD = new ConcreteComponentD(mediator);
        componentA.send("i am a", componentB);
        componentB.send("i am b", componentC);
        componentC.send("i am c", componentD);
        componentD.send("i am d", componentA);
    }
}

public class Sender {
    private String message;

    private Component source;

    private Component target;

    public Sender(String message, Component source, Component target) {
        this.message = message;
        this.source = source;
        this.target = target;
    }

    public String getMessage() {
        return this.message;
    }

    public Component getSource() {
        return this.source;
    }

    public Component getTarget() {
        return this.target;
    }
}

适用场景

在以下情况下可以考虑使用中介者模式:
(1) 当一些对象和其他对象紧密耦合,产生的相互依赖关系结构混乱且难以理解,从而导致难以对其进行修改时,可考虑使用中介者模式。中介者模式可将对象间的所有关系抽取成为一个单独的类,
以使对于特定组件的修改工作独立于其他组件。
(2) 当组件因过于依赖其他组件而无法在不同应用中复用时,可考虑使用中介者模式。应用中介者模式后, 每个组件不再知晓其他组件的情况。尽管这些组件无法直接交流,但它们仍可通过中介者对象进行间接交流。
如果希望在不同应用中复用一个组件,则需要为其提供一个新的中介者类。
(3) 如果为了能在不同情景下复用一些基本行为,导致需要被迫创建大量组件子类时,可考虑使用中介者模式。由于所有组件间关系都被包含在中介者中, 因此无需修改组件就能方便地新建中介者类以定义新的组件合作方式。

优缺点

中介者模式有以下优点:
(1) 符合单一职责原则。可以将多个组件间的交流抽取到同一位置,使其更易于理解和维护。
(2) 符合开闭原则。无需修改实际组件就能增加新的中介者。
(3) 可以减轻应用中多个组件间的耦合情况。
但是该模式也存在以下缺点:
(1) 在具体中介者类中包含了组件之间的交互细节,可能会导致具体中介者类非常复杂,使得系统难以维护。一段时间后,中介者可能会演化成为上帝对象。

参考

《设计模式 可复用面向对象软件的基础》 Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides 著, 李英军, 马晓星等译
https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/mediator.html 中介者模式
https://refactoringguru.cn/design-patterns/mediator 中介者模式
https://www.runoob.com/design-pattern/mediator-pattern.html 中介者模式
https://www.cnblogs.com/adamjwh/p/10959987.html 简说设计模式——中介者模式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/847222.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【设计模式——学习笔记】23种设计模式——中介者模式Observer(原理讲解+应用场景介绍+案例介绍+Java代码实现)

文章目录 案例引入案例一普通实现中介者模式 案例二 介绍基础介绍登场角色尚硅谷 《图解设计模式》 案例实现案例一:智能家庭类图实现 案例二:登录页面逻辑实现说明类图实现 总结文章说明 案例引入 案例一 普通实现 在租房过程中,客户可能…

回看雷军演讲,我对项目经理人的发展又有了2点想法……

大家好,我是老原。 最近在回看一些大佬演讲,看到雷军的演讲时,说实话我蛮激动的,最近常有粉丝朋友找我闲聊,也工作十几年,不知道怎么才能寻求突破? 而小米本身,不就是一直在突破吗…

C高级-day4

#!/bin/bash function fun1(){arr[0]id -u $1arr[1]id -g $1echo ${arr[*]} }arr(fun1 ubuntu) echo ${arr[*]}冒泡排序 void Maopao(int arr[],int len){for(int i1;i<len;i){int count0;for(int j0;j<len-i;j){if(arr[j]>arr[j1]){int tarr[j];arr[j]arr[j1];arr[j…

嵌入式Linux下LVGL的移植与配置

一.sdk源码下载路径 1.官方源码下载路径如下: ​​​​​​ https://github.com/lvgl/lvgl git下载方式 git clone https://github.com/lvgl/lvgl.git 2.个人移植好的源码8.2版本下载路径: 链接:https://pan.baidu.com/s/1jyqIennsQpv-RB4RyKvZyg?pwd=c68e 提取码:c68e…

《HeadFirst设计模式(第二版)》第七章代码——外观模式

代码文件目录&#xff1a; Subsystem: Amplifier package Chapter7_AdapterAndFacadePattern.FacadePattern.Subsystem;/*** Author 竹心* Date 2023/8/8**///扬声器 public class Amplifier {int volume 0;//音量public void on(){System.out.println("The amplifier …

redis 的副本和分片

什么是分片 分片也叫条带&#xff0c;指Redis集群的一个管理组&#xff0c;对应一个redis-server进程。一个Redis集群由若干条带组成&#xff0c;每个条带负责若干个slot&#xff08;槽&#xff09;&#xff0c;数据分布式存储在slot中。Redis集群通过条带化分区&#xff0c;实…

数据库优化:探索 SQL 中的索引

推荐&#xff1a;使用 NSDT场景编辑器 助你快速搭建可编辑的3D应用场景 在一本书中搜索特定主题时&#xff0c;我们将首先访问索引页面&#xff08;该页面位于该书的开头&#xff09;&#xff0c;并找到包含我们感兴趣的主题的页码。现在&#xff0c;想象一下在没有索引页的书中…

python_面向对象基础_数据分析

主要目的 对于文本格式和JSON格式数据进行分析&#xff0c;将其中数据提炼出来绘制折线图。 主要实现步骤 1.设计一个完成对数据的封装 2.设计一个抽象类,定义数据读取相关功能,使用其子类实现具体功能 3.读取文件,生成数据对象 4.进行数据计算 5.绘制图表 定义数据封装类 &…

Annotorious.js 入门教程:图片注释工具

theme: smartblue 本文简介 【今天我必须发一个封面&#xff01;放文末&#xff01;】 最近有工友问我前端怎么给图片做标注。使用 Fabric.js 或者 Konva.js 等库确实可以实现&#xff0c;但多少觉得有点大炮打蚊的感觉&#xff0c;好奇有没有专门做图片标注的工具呢&#xff1…

剑指offer(C++)-JZ16:数值的整数次方(算法-位运算)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 题目描述&#xff1a; 实现函数 double Power(double base, int exponent)&#xff0c;求base的exponent次方。 注意&#xff1…

stm32项目(5)——基于stm32的工地噪声扬尘检测系统

目录 1.功能设计 2.硬件方案 1.单片机选择 2.声音传感器 3.PM2.5传感器 4.显示器 3.程序设计 4.课题意义 1.功能设计 本次系统实现的功能如下所示&#xff1a; 采用声音传感器检测环境噪音&#xff0c;采用PM2.5传感器检测环境灰尘浓度。若噪声超过阈值或者PM2.5超过阈…

ROS Navigation Stack安装

Navigation导航包是做导航几乎都要用的&#xff0c;大家可以先去ROS Wiki上学习下 我们先Git下对应版本的软件包&#xff0c;我是Kinetic的&#xff0c;所以是Kinetic-devel 下载后发现目录下并没有CMakeLists.txt&#xff0c;所以直接在ROS工作目录下catkin_make并不会产生可…

【FPGA】UART串口通信——奇偶校验实现

文章目录 一、奇偶校验位二、设计思路三、仿真测试 一、奇偶校验位 奇偶校验位是基于uart的数据上进行一个判断 奇校验&#xff1a;数据1个数为奇时&#xff0c;校验为0&#xff0c;反之为1 偶校验&#xff1a;数据0个数为偶时&#xff0c;校验为0&#xff0c;反之为1 Uart…

MySQL 事务原理:事务概述、隔离级别、MVCC

文章目录 一、事务1.1 事务概述1.2 事务控制语句1.3 ACID特性 二、隔离级别2.1 隔离级别的分类2.1.1 读未提交&#xff08;RU&#xff09;2.1.2 读已提交&#xff08;RC&#xff09;2.1.3 可重复读&#xff08;RR&#xff09;2.1.4 串行化 2.2 命令2.3 并发读异常2.3.1 脏读2.3…

Babylon.js着色器简明简称【Shader】

推荐&#xff1a;用 NSDT设计器 快速搭建可编程3D场景 为了生成 BabylonJS 场景&#xff0c;需要用 Javascript 编写代码&#xff0c;BabylonJS 引擎会处理该代码并将结果显示在屏幕上。 场景可以通过改变网格、灯光或摄像机位置来改变。 为了及时显示可能的变化&#xff0c;屏…

借助gopsutil库,获取机器相关信息

使用github.com/shirou/gopsutil/disk这个库&#xff0c;如何获取机器下不同磁盘分区的内容 使用 github.com/shirou/gopsutil/disk 库获取机器下不同磁盘分区的内容&#xff0c;可按如下&#xff1a; import "github.com/shirou/gopsutil/disk"//调用 disk.Partitio…

【瑞吉外卖】Git部分学习

Git简介 Git是一个分布式版本控制工具&#xff0c;通常用来对软件开发过程中的源代码文件进行管理。通过Git仓库来存储和管理这些文件&#xff0c;Git仓库分为两种&#xff1a; 本地仓库&#xff1a;开发人员自己电脑上的Git仓库 远程仓库&#xff1a;远程服务器上的Git仓库…

git原理与使用

目录 引入基本操作分支管理远程操作标签管理 引入 假设你的老板要你设计一个文档&#xff0c;当你设计好了&#xff0c;拿给他看时&#xff0c;他并不是很满意&#xff0c;就要你拿回去修改&#xff0c;你修改完后&#xff0c;再给他看时&#xff0c;他还是不满意&#xff0c;…

ERP、APS、MES 三者之间的关系

ERP&#xff08;Enterprise Resource Planning&#xff09; APS&#xff08;Advanced Planning and Scheduling&#xff09; MES&#xff08;Manufacturing Execution System&#xff09; 这是三种不同类型的软件系统&#xff0c;它们主要用于企业内部管理和自动化运营流程。…

vscode Google代码风格设置无效解决

1. 采用第一个方法设置google代码设置风格 2. 安装了clangd后需要在格式化风格做选择 vscode 安装 clang-format插件 $ code /home/tony/.config/Code/User/settings.json 这就能解决google风格设置无效的问题了&#xff0c;原来根因在于使用的格式化插件没有生效导致&#xf…