当前位置: 首页 > news >正文

化繁为简:中介者模式如何管理复杂对象交互

化繁为简:中介者模式如何管理复杂对象交互

中介者模式 是一种行为型设计模式,定义了一个中介者对象,来封装一组对象之间的交互。中介者模式通过将对象之间的交互行为从多个对象中抽离出来,集中封装在一个中介者对象中,从而使各个对象之间的耦合松散,且可以独立地改变它们之间的交互。

核心思想

中介者模式通过引入一个中介者,协调多个对象之间的交互,避免对象之间的直接通信,从而减少对象之间的耦合

中介者模式的组成角色

Mediator(中介者接口)

  • 中介者定义了对象之间交互的接口,负责协调各个对象之间的通信行为。

ConcreteMediator(具体中介者)

  • 实现了 Mediator 接口,协调各具体同事对象之间的交互。它了解所有的同事对象,并通过其实现交互逻辑。

Colleague(同事类)

  • 每个同事对象只知道中介者,不能直接与其他同事对象通信。所有的交互都通过中介者来完成。

ConcreteColleague(具体同事类)

  • 实现了 Colleague 接口,依赖中介者与其他同事对象通信。每个具体同事对象的行为受到中介者的约束。

中介者模式的 UML 类图

在这里插入图片描述

类图解释

  1. Mediator(中介者接口):定义了同事对象之间的通信接口,通常定义 send() 方法来协调通信。
  2. ConcreteMediator(具体中介者)
    • 实现了 Mediator 接口,具体负责管理和协调同事对象之间的通信。它知道所有的具体同事对象,并通过 send() 方法传递消息或协调操作。
    • 它也可以持有具体的同事对象的引用,负责管理这些对象。
  3. Colleague(同事类):抽象类或接口,每个同事对象依赖中介者与其他同事进行交互。它不直接与其他同事对象通信,而是通过中介者通信。
  4. ConcreteColleague1、ConcreteColleague2(具体同事类):实现 Colleague,定义各自的具体操作。同事对象通过中介者协调相互间的通信

工作原理

  1. 集中通信:中介者模式通过引入 Mediator,将多个对象之间的交互逻辑集中到中介者中,使得各个同事类之间的关系变得松散耦合。
  2. 消息传递:同事对象通过调用中介者的 send() 方法进行通信。中介者负责接收和转发消息,并协调其他同事对象的行为。
  3. 解耦同事对象:同事对象之间不直接交互,而是通过中介者来处理。这样一来,各个对象之间的依赖关系被削弱了。

案例:机场塔台与飞机的调度

场景说明

在机场,飞机起飞和降落的调度是一个非常复杂的过程。如果每架飞机都直接与其他飞机进行通信,会导致混乱并增加空中事故的风险。因此,机场有一个控制塔(塔台),它负责协调所有飞机的起飞和降落

控制塔是中介者,飞机之间的所有通信都必须通过控制塔进行。飞机通过塔台来获取是否可以起飞或降落,从而避免与其他飞机发生冲突。

中介者模式的角色在机场塔台场景中的映射:

  1. Mediator(中介者接口):机场控制塔,负责协调所有飞机的起飞和降落。
  2. ConcreteMediator(具体中介者):具体实现的控制塔,协调飞机的飞行状态。
  3. Colleague(同事类):抽象飞机类,代表参与通信的对象(飞机)。
  4. ConcreteColleague(具体同事类):具体的飞机类,通过控制塔来决定起飞或降落。

在这里插入图片描述

代码实现:机场塔台调度系统

Step 1: 定义中介者接口

中介者接口定义了调度方法,用于协调飞机之间的通信。

// 中介者接口:塔台
public interface Mediator {void notify(String message, Airplane airplane);
}

Step 2: 实现具体的中介者

ControlTower 类是具体的中介者,它负责接收飞机的状态并通知其他飞机,确保起飞和降落顺序的安全。

import java.util.ArrayList;
import java.util.List;// 具体中介者:控制塔
public class ControlTower implements Mediator {private List<Airplane> airplanes;public ControlTower() {this.airplanes = new ArrayList<>();}public void registerAirplane(Airplane airplane) {airplanes.add(airplane);}@Overridepublic void notify(String message, Airplane airplane) {for (Airplane a : airplanes) {if (a != airplane) {a.receive(message);  // 通知其他飞机}}}
}

Step 3: 定义飞机抽象类

飞机类通过中介者来发送和接收信息,而不直接与其他飞机通信。

// 飞机抽象类
public abstract class Airplane {protected Mediator mediator;protected String name;public Airplane(Mediator mediator, String name) {this.mediator = mediator;this.name = name;}public abstract void send(String message);public abstract void receive(String message);
}

Step 4: 实现具体飞机类

具体飞机类实现了 send()receive() 方法,通过塔台来发送和接收消息。

Boeing737 类

// 具体飞机:Boeing 737
public class Boeing737 extends Airplane {public Boeing737(Mediator mediator, String name) {super(mediator, name);}@Overridepublic void send(String message) {System.out.println(this.name + " sends message: " + message);mediator.notify(message, this);  // 通过塔台发送消息}@Overridepublic void receive(String message) {System.out.println(this.name + " receives message: " + message);}
}

AirbusA320 类

// 具体飞机:Airbus A320
public class AirbusA320 extends Airplane {public AirbusA320(Mediator mediator, String name) {super(mediator, name);}@Overridepublic void send(String message) {System.out.println(this.name + " sends message: " + message);mediator.notify(message, this);  // 通过塔台发送消息}@Overridepublic void receive(String message) {System.out.println(this.name + " receives message: " + message);}
}

Step 5: 测试中介者模式

通过 ControlTower 来协调 Boeing737AirbusA320 之间的通信,确保飞机的起飞和降落顺序。

public class MediatorPatternDemo {public static void main(String[] args) {// 创建控制塔ControlTower tower = new ControlTower();// 创建飞机并注册到塔台Airplane boeing737 = new Boeing737(tower, "Boeing 737");Airplane airbusA320 = new AirbusA320(tower, "Airbus A320");tower.registerAirplane(boeing737);tower.registerAirplane(airbusA320);// 飞机发送消息boeing737.send("Requesting permission to land.");airbusA320.send("Requesting permission to take off.");}
}

输出结果

Boeing 737 sends message: Requesting permission to land.
Airbus A320 receives message: Requesting permission to land.
Airbus A320 sends message: Requesting permission to take off.
Boeing 737 receives message: Requesting permission to take off.

中介者模式在机场塔台场景中的工作原理

  1. 集中通信:所有的飞机(同事类)不直接通信,而是通过控制塔(中介者)进行协调。每架飞机都通过塔台发送和接收消息。
  2. 消息传递:当一架飞机发送起飞或降落请求时,塔台负责通知其他飞机,并保证飞行安全和秩序。
  3. 降低耦合性:飞机之间不直接通信,所有交互通过塔台完成,从而降低了飞机之间的耦合,增强了系统的灵活性和扩展性。

SpringMVC 中的 应用

Spring Framework 中,DispatcherServlet 作为前端控制器,实际上也承担了类似于中介者的作用。它在 Spring MVC 架构中负责协调不同组件(如控制器、视图解析器和处理器)的交互。

原理
  • DispatcherServlet 作为一个统一的请求分发器,负责接收 HTTP 请求,并根据请求的 URL 或其他条件,将请求分发给适当的处理器(如 @Controller 的方法)。它并不直接参与具体的请求处理,而是协调多个组件来完成请求-响应的流程。
  • 控制器、视图解析器、处理器等组件之间不直接通信,而是通过 DispatcherServlet 进行交互。
// DispatcherServlet 伪代码,简化示例
public class DispatcherServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 根据请求查找对应的控制器Handler handler = getHandler(request);// 调用控制器处理请求ModelAndView mv = handler.handleRequest(request, response);// 解析视图并返回响应render(mv, response);}
}

在这里,DispatcherServlet 类似于中介者,协调多个组件之间的交互,不同的控制器和视图解析器不直接互相通信,而是通过 DispatcherServlet 进行处理。

中介者模式的优缺点与应用场景总结

优点:

  1. 降低对象之间的耦合性
    • 中介者模式通过引入中介者,使多个对象之间的依赖关系转变为与中介者的依赖,减少了对象之间的直接交互,降低了系统的耦合度。
  2. 简化对象之间的通信
    • 所有通信都通过中介者集中管理,使得系统结构更加清晰,逻辑集中,尤其在多方通信的复杂系统中,简化了交互逻辑。
  3. 符合开闭原则
    • 中介者模式可以方便地扩展或修改交互逻辑,而不影响各个同事对象。可以通过修改中介者来增加或调整各对象之间的交互。
  4. 提高系统的灵活性
    • 当需要增加新的对象或修改对象之间的交互行为时,可以通过中介者进行控制,增强了系统的扩展性和灵活性。

缺点:

  1. 中介者可能变得复杂
    • 随着系统中同事对象的增多,中介者需要处理的交互逻辑也会变得越来越复杂,可能导致中介者变得难以维护,形成一个“上帝对象”。
  2. 不适合简单场景
    • 如果对象之间的交互非常简单,使用中介者模式会引入不必要的复杂性,增加维护成本。

应用场景:

  1. 复杂对象交互的系统
    • 在多个对象之间存在复杂交互的系统中,中介者模式非常适用。例如,GUI 控件交互(如按钮、文本框、下拉菜单等)可以通过中介者来管理。
  2. 消息队列系统
    • 在消息队列(如 JMS)中,中介者管理生产者和消费者之间的消息传递,解耦了消息的发送和接收,避免直接通信。
  3. 事件驱动系统
    • 在事件驱动架构中,事件发布者和监听者之间的通信可以通过中介者来协调,避免对象之间的紧密耦合。例如,Spring 的事件驱动机制利用 ApplicationEventPublisherApplicationListener 解耦了事件发布和处理。
  4. 航空管制系统
    • 像机场塔台这种需要协调多架飞机起降的系统,中介者可以集中管理对象的行为,保证复杂交互的有序进行。

相关文章:

化繁为简:中介者模式如何管理复杂对象交互

化繁为简&#xff1a;中介者模式如何管理复杂对象交互 中介者模式 是一种行为型设计模式&#xff0c;定义了一个中介者对象&#xff0c;来封装一组对象之间的交互。中介者模式通过将对象之间的交互行为从多个对象中抽离出来&#xff0c;集中封装在一个中介者对象中&#xff0c;…...

控制STM32蜂鸣器示例代码(江科大)

以下代码来源于本人学习江科大的课程&#xff0c;这是一个简单的STM32微控制器程序&#xff0c;用于控制连接到GPIOB第12号引脚的蜂鸣器。程序通过GPIOB的第12号引脚输出PWM波形来控制蜂鸣器的频率&#xff0c;从而产生声音。 #include "stm32f10x.h" …...

Java基础知识扫盲

目录 Arrays.sort的底层实现 BigDecimal(double)和BigDecimal(String)有什么区别 Char可以存储一个汉字吗 Java中的Timer定时调度任务是咋实现的 Java中的序列化机制是咋实现的 Java中的注解是干嘛的 Arrays.sort的底层实现 Arrays.sort是Java中提供的对数组进行排序的…...

ZLMediaKit Windows编译以及使用

1.运行ZLMediaKit 2.通过ffmpeg把视频源推流给ZLMediaKit 执行以下命令&#xff0c;将本地视频通过RTSP协议推流给ZLMediaKit。 ffmpeg -re -stream_loop -1 -i "D:\workplace\armgb\public\1.fileh264" -vcodec h264 -f rtsp rtsp://127.0.0.1/live/test 若想将本…...

基于YOLOv5s的无人机航拍输电线瓷瓶检测(附数据集与操作步骤)

本文主要内容:详细介绍了无人机航拍输电线瓷瓶检测的整个过程&#xff0c;从创建数据集到训练模型再到预测结果全部可视化操作与分析。 文末有数据集获取方式&#xff0c;请先看检测效果 现状 输电线路绝缘瓷瓶的检测主要依赖人工巡检。巡检人员需携带专业设备&#xff0c;攀…...

【Python百日进阶-Web开发-FastAPI】Day805 - FastAPI的请求体

文章目录 一、导入 Pydantic 的 BaseModel二、创建数据模型三、声明为参数四、结果五、自动化文档六、编辑器支持七、使用模型八、请求体 + 路径参数九、请求体 + 路径参数 + 查询参数十、不使用 Pydantichttps://fastapi.tiangolo.com/zh/tutorial/body/ 当你需要将数据从客户…...

【Kubernetes】常见面试题汇总(二十八)

目录 79.您如何看待公司从单一服务转向微服务并部署其服务容器&#xff1f; 80.什么是 Headless Service&#xff1f; 特别说明&#xff1a; 题目 1-68 属于【Kubernetes】的常规概念题。 题目 69-113 属于【Kubernetes】的生产应用题。 79.您如何看待公司从单一服务转…...

单ISP与双ISP的区别是什么

单ISP&#xff08;单一互联网服务提供商&#xff09;与双ISP&#xff08;双重互联网服务提供商&#xff09;主要在以下几个方面有区别&#xff1a; 服务冗余&#xff1a; 单ISP&#xff1a;只有一个互联网服务提供商提供的网络连接。如果该ISP发生故障&#xff0c;整个网络连接…...

【linux】gcc makefile

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;linux笔记仓 目录 01.gcc如何完成02.gcc选项03.函数库与动静态链接静态链接动态链接库文件特点和用途动态链接版本和兼容性 04.makefile自动推导 01.gcc如何完成 预处理(进行宏替换) 预处理功能主要…...

12.Java基础概念-面向对象-static

欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 Facts speak louder than words&#xff01; 一、static关键字的含义…...

移动开发(三):使用.NET MAUI打包第一个安卓APK完整过程

目录 一、修改AndroidManifest.xml 配置APP基本信息权限 二、修改项目属性调整输出Android包格式为APK 三、项目发布 四、APP分发 五、总结 之前给大家介绍过使用使用.NET MAUI开发第一个安卓APP,今天给大家介绍如何打包成APK,然后安装到安卓手机正常运行。这里还是沿用…...

数据库中的DUAL表

在日常的数据库操作中&#xff0c;DUAL表是一个特殊的存在。它是一个伪表&#xff0c;用于在不需要实际数据表的情况下进行简单的查询。特别是在执行一些无关联的数据计算时&#xff0c;DUAL表经常派上用场。 什么是DUAL表&#xff1f; DUAL表最早出现在Oracle数据库中&#…...

寄宿制学校自闭症教育:为每个孩子创造奇迹

寄宿制学校自闭症教育&#xff1a;星贝育园——为每个孩子创造奇迹 在自闭症儿童教育的广阔领域中&#xff0c;寄宿制学校以其独特的教育模式和全方位的关怀体系&#xff0c;正逐步成为推动这些特殊孩子成长与发展的重要力量。广州的星贝育园自闭症儿童寄宿制学校&#xff0c;…...

Vue前端无法接收到后端返回的数据以及全局CSS样式影响(已解决)

Vue前端无法接收到后端返回的数据 前提&#xff1a;把很久以前的项目&#xff0c;翻出来重新优化一下&#xff0c;做一下前端的美化&#xff08;以前都是用的element的UI&#xff0c;现在想自己写&#xff09;。 由于是自己利用简单的html语句&#xff0c;主要面向各个按钮控…...

力扣234 回文链表 Java版本

文章目录 题目描述代码 题目描述 给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为 回文链表 。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,2,1] 输出&#xff1a;true 示例 2&…...

银行性能测试怎么做?来认识下这4个性能测试工具!

一、银行项目性能测试是什么&#xff1f; 银行项目性能测试是一种软件测试形式&#xff0c;用于评估银行应用程序的性能和负载能力。 它的主要目标是确保银行系统能够在不同负载水平下提供稳定、高效的服务。 性能测试涵盖了多个方面&#xff0c;包括响应时间、吞吐量、并发用…...

FME学习笔记

读取数据 方法一&#xff1a;add reader 通过读模块来进行数据的读取 方法二&#xff1a;FeatureReader Parameters 通过转换器来进行数据的读取 可以通过空间范围进行筛选 在FME中&#xff0c;所有数据处理都要用到的&#xff0c;绝对的重点&#xff1a;转换器&#xff…...

机器翻译之创建Seq2Seq的编码器、解码器

1.创建编码器、解码器的基类 1.1创建编码器的基类 from torch import nn#构建编码器的基类 class Encoder(nn.Module): #继承父类nn.Moduledef __init__(self, **kwargs): #**kwargs&#xff1a;不定常的关键字参数super().__init__(**kwargs)def forward(self, X, *args…...

锤炼核心技能以应对编程革命

一、引言  随着人工智能的快速发展&#xff0c;尤其是AIGC等大语言模型的涌现&#xff0c;AI辅助编程工具逐渐成为程序员的新伙伴。这一变革不仅引发了关于AI是否能取代部分编程工作的讨论&#xff0c;也促使程序员重新思考自己的职业发展和技能提升路径。在AI时代&#xff0…...

2024 go-zero社交项目实战

背景 一位商业大亨&#xff0c;他非常看好国内的社交产品赛道&#xff0c;想要造一款属于的社交产品&#xff0c;于是他找到了负责软件研发的小明。 小明跟张三一拍即合&#xff0c;小明决定跟张三大干一番。 社交产品MVP版本需求 MVP指&#xff1a;Minimum Viable Product&…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

中医有效性探讨

文章目录 西医是如何发展到以生物化学为药理基础的现代医学&#xff1f;传统医学奠基期&#xff08;远古 - 17 世纪&#xff09;近代医学转型期&#xff08;17 世纪 - 19 世纪末&#xff09;​现代医学成熟期&#xff08;20世纪至今&#xff09; 中医的源远流长和一脉相承远古至…...

Webpack性能优化:构建速度与体积优化策略

一、构建速度优化 1、​​升级Webpack和Node.js​​ ​​优化效果​​&#xff1a;Webpack 4比Webpack 3构建时间降低60%-98%。​​原因​​&#xff1a; V8引擎优化&#xff08;for of替代forEach、Map/Set替代Object&#xff09;。默认使用更快的md4哈希算法。AST直接从Loa…...

WebRTC从入门到实践 - 零基础教程

WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC&#xff1f; WebRTC&#xff08;Web Real-Time Communication&#xff09;是一个支持网页浏览器进行实时语音…...

Spring Boot + MyBatis 集成支付宝支付流程

Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例&#xff08;电脑网站支付&#xff09; 1. 添加依赖 <!…...

32单片机——基本定时器

STM32F103有众多的定时器&#xff0c;其中包括2个基本定时器&#xff08;TIM6和TIM7&#xff09;、4个通用定时器&#xff08;TIM2~TIM5&#xff09;、2个高级控制定时器&#xff08;TIM1和TIM8&#xff09;&#xff0c;这些定时器彼此完全独立&#xff0c;不共享任何资源 1、定…...