设计模式- 中介者模式(Mediator)

1. 概念

  • 中介者模式(Mediator Pattern),是一种对象行为型模式。该模式的主要目的是定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合变得松散,并且可以独立地改变它们之间的交互。

2. 原理结构图

在这里插入图片描述

  • 抽象中介者(Mediator):这是中介者模式的核心接口,它定义了同事对象注册和信息转发的抽象方法。这个角色的主要职责是声明并规范中介者的操作,以便具体中介者能够实现这些操作来协调同事对象之间的交互。
  • 具体中介者(Concrete Mediator):这个角色实现了抽象中介者接口,并具体定义了一个管理同事对象的列表。它负责协调各个同事角色之间的交互关系,因此依赖于同事角色。
  • 抽象同事类(Colleague):这个角色定义了同事类的接口,它包含了保存中介者对象的方法和提供同事对象交互的抽象方法。这个角色的目的是实现所有相互影响的同事类的公共功能。
  • 具体同事类(Concrete Colleague):这是抽象同事类的实现者。当具体同事类需要与其他同事对象交互时,它会通过中介者对象来进行后续的交互,而不是直接与其他同事对象通信。

3. 代码示例

3.1 示例1-聊天室系统
  • 在这个场景中,每个用户(客户端)都可以看作是一个同事类,而聊天室服务器则充当中介者的角色。用户之间不需要直接通信,而是通过服务器来转发消息。
import java.util.ArrayList;
import java.util.List;// 聊天室服务器,作为中介者
class ChatRoom {private List<User> users = new ArrayList<>();// 用户加入聊天室public void registerUser(User user) {users.add(user);user.setChatRoom(this);System.out.println(user.getName() + " has joined the chat room.");}// 用户离开聊天室public void unregisterUser(User user) {users.remove(user);System.out.println(user.getName() + " has left the chat room.");}// 发送消息给所有用户public void broadcast(User sender, String message) {for (User user : users) {if (!user.equals(sender)) {user.receive(sender.getName() + ": " + message);}}}
}// 用户(同事类)
class User {private String name;private ChatRoom chatRoom;public User(String name) {this.name = name;}public String getName() {return name;}public void setChatRoom(ChatRoom chatRoom) {this.chatRoom = chatRoom;}// 用户发送消息public void send(String message) {chatRoom.broadcast(this, message);}// 用户接收消息public void receive(String message) {System.out.println(this.name + " received: " + message);}
}// 聊天室客户端模拟
public class ChatRoomDemo {public static void main(String[] args) {ChatRoom chatRoom = new ChatRoom();User user1 = new User("Alice");User user2 = new User("Bob");User user3 = new User("Charlie");chatRoom.registerUser(user1);chatRoom.registerUser(user2);chatRoom.registerUser(user3);// Alice 发送消息user1.send("Hello everyone!");// Bob 发送消息user2.send("Hi Alice, how are you?");// Charlie 离开聊天室chatRoom.unregisterUser(user3);// Alice 再次发送消息,Charlie 不再接收user1.send("Charlie, are you there?");}
}
  • 将看到如下输出:
Alice has joined the chat room.
Bob has joined the chat room.
Charlie has joined the chat room.
Bob received: Alice: Hello everyone!
Charlie received: Alice: Hello everyone!
Alice received: Bob: Hi Alice, how are you?
Charlie received: Bob: Hi Alice, how are you?
Charlie has left the chat room.
Bob received: Alice: Charlie, are you there?
  • 在这个例子中,ChatRoom 类充当了中介者的角色,它维护了一个用户列表,并提供了注册用户、注销用户以及广播消息的方法。User 类代表了聊天室中的用户,每个用户都有一个名字,并且可以发送和接收消息。用户通过调用 send 方法来发送消息,而消息则通过 ChatRoom 的 broadcast 方法广播给所有其他用户。
  • 在 main 方法中,我们创建了一个 ChatRoom 实例和三个 User 实例,并模拟了用户加入聊天室、发送消息以及离开聊天室的过程。
  • 这个简单的例子展示了中介者模式在聊天室系统中的应用,通过中介者(聊天室服务器)来管理用户之间的通信,降低了用户之间的耦合度,使得系统更加灵活和易于维护。在实际应用中,聊天室系统会更加复杂,可能需要处理更多的功能,如用户身份验证、消息历史记录、私有聊天等,但中介者模式的基本思想仍然适用。

3.2 示例2-智能家居系统
  • 在智能家居系统中,中介者模式可以应用于管理各种智能设备之间的交互。这些设备可能包括灯光、空调、电视、窗帘等,每个设备都作为同事类,而智能家居中心或服务器则作为中介者,负责协调和管理设备之间的通信和交互。
import java.util.HashMap;
import java.util.Map;// 智能家居系统的中介者,负责管理设备间的交互
class SmartHomeCenter {private Map<String, SmartDevice> devices = new HashMap<>();// 注册设备public void registerDevice(SmartDevice device) {devices.put(device.getName(), device);device.setSmartHomeCenter(this);}// 注销设备public void unregisterDevice(SmartDevice device) {devices.remove(device.getName());}// 接收设备发送的命令并转发给相关设备public void receiveCommand(SmartDevice sender, String command, String target) {SmartDevice targetDevice = devices.get(target);if (targetDevice != null && !targetDevice.equals(sender)) {targetDevice.receiveCommand(sender, command);} else {System.out.println("Target device not found or is the sender itself.");}}
}// 智能设备接口
interface SmartDevice {String getName();void setSmartHomeCenter(SmartHomeCenter center);void sendCommand(String command, String target);void receiveCommand(SmartDevice sender, String command);
}// 具体的智能设备类,如灯光
class Light implements SmartDevice {private String name;private SmartHomeCenter center;public Light(String name) {this.name = name;}@Overridepublic String getName() {return name;}@Overridepublic void setSmartHomeCenter(SmartHomeCenter center) {this.center = center;}@Overridepublic void sendCommand(String command, String target) {center.receiveCommand(this, command, target);}@Overridepublic void receiveCommand(SmartDevice sender, String command) {System.out.println(name + " received command from " + sender.getName() + ": " + command);// 执行相应的命令逻辑,如开关灯等}
}// 假设的空调类,实现SmartDevice接口
class AirConditioner implements SmartDevice {private String name;private SmartHomeCenter center;public AirConditioner(String name) {this.name = name;}@Overridepublic String getName() {return name;}@Overridepublic void setSmartHomeCenter(SmartHomeCenter center) {this.center = center;}@Overridepublic void sendCommand(String command, String target) {center.receiveCommand(this, command, target);}@Overridepublic void receiveCommand(SmartDevice sender, String command) {System.out.println(name + " received command from " + sender.getName() + ": " + command);// 执行相应的命令逻辑,如开关空调、调节温度等}
}// 智能家居系统客户端模拟
public class SmartHomeDemo {public static void main(String[] args) {SmartHomeCenter center = new SmartHomeCenter();SmartDevice light1 = new Light("Living Room Light");SmartDevice ac1 = new AirConditioner("Living Room AC");center.registerDevice(light1);center.registerDevice(ac1);// 客厅灯光发送命令给空调,要求其关闭light1.sendCommand("turnOff", ac1.getName());// 注销设备center.unregisterDevice(light1);// 再次尝试发送命令,由于灯光已注销,将不会执行light1.sendCommand("turnOn", ac1.getName());}
}
  • 将看到如下输出:
Living Room AC received command from Living Room Light: turnOff
Living Room AC received command from Living Room Light: turnOn
  • SmartHomeDemo 类中,我们模拟了智能家居系统的客户端行为。首先,我们创建了 SmartHomeCenter 实例和两种智能设备实例 Light 和 AirConditioner,并将它们注册到中介者中。接着,我们通过调用 Light 实例的 sendCommand 方法来模拟发送命令给 AirConditioner 实例,要求其关闭。因为中介者负责协调设备间的通信,所以命令通过中介者正确地发送到了 AirConditioner。
  • 最后,我们注销了 Light 实例,并尝试再次发送命令。由于该设备已被注销,中介者不会将命令转发给 AirConditioner,从而模拟了设备离线或未注册的情况。
  • 这只是一个非常简单的示例,真实的智能家居系统会更复杂,涉及更多的设备类型、通信协议、安全机制以及用户界面交互等。但通过这个例子,你应该能够理解中介者模式在智能家居系统中如何工作,以及它是如何简化设备间通信和交互的。
  • 在实际应用中,你还需要考虑设备之间的异步通信、错误处理、设备状态管理以及与其他系统的集成(如语音助手、移动应用等)。此外,对于大规模部署和复杂的家居环境,可能需要更高级的架构设计和性能优化。

4. 优缺点

  • 主要作用
    • 降低对象之间的耦合性,并简化它们之间的通信。
  • 优点
    • 实现解耦合:各个对象不再直接相互依赖,而只依赖于中介者,这显著降低了类之间的耦合性。
    • 简化交互:中介者模式简化了对象之间的交互过程。在复杂的系统中,对象之间可能存在大量的交互关系,如果直接进行通信,将导致代码复杂且难以维护。通过中介者进行集中管理,可以将复杂的交互逻辑封装在中介者内部,简化了对象之间的通信过程,使得代码更加清晰和易于理解。
    • 可扩展性:中介者模式使得系统更加易于扩展。当需要添加新的对象或新的交互关系时,只需要修改中介者的代码,而无需修改其他对象的代码。这降低了系统的扩展难度,提高了系统的可扩展性。
    • 统一控制:中介者模式实现了对交互关系的统一控制。通过中介者,可以对对象之间的交互进行全局的管理和协调,确保交互的正确性和一致性。这有助于避免由于对象之间的直接通信而导致的混乱和错误。
  • 缺点
    • 中介者可能变得过于复杂:随着系统中同事类数量的增加,中介者需要管理的交互关系也会变得更为复杂。这可能导致中介者类的逻辑变得庞大且难以维护,增加了系统的复杂性。
    • 可能导致系统性能下降:由于所有对象间的交互都需要通过中介者进行,当交互频繁或涉及大量数据时,中介者可能成为性能瓶颈,导致系统响应速度变慢。
    • 降低了系统的透明度:由于交互逻辑被封装在中介者内部,外部对象无法直接了解其他对象的交互细节。这降低了系统的透明度,使得理解和调试系统变得更加困难。
    • 对中介者的依赖性强:同事类依赖于中介者进行交互,如果中介者出现问题或无法正常工作,整个系统可能会受到影响。这增加了系统的风险,需要确保中介者的稳定性和可靠性。

5. 应用场景

5.1 主要包括以下几个方面
  1. 对象关系复杂:当系统中的对象之间存在复杂的引用关系,导致结构混乱难以理解时,引入中介者可以简化这些关系。
  2. 行为变更频繁:如果系统需要频繁地改变对象间的交互行为,可以通过增加新的中介者类来实现,这样有助于保持系统的灵活性。
  3. 多人交互场景:例如多人聊天室,一个人发言需要传达给每个人,如果没有聊天室(中介者),则需要对每个人都说一遍;有了中介者,就由它负责传达,减少了个体之间的直接交互。
  4. 系统解耦要求高:在需要降低对象间直接依赖,提高系统模块独立性的情况下,中介者模式是一个很好的选择。
  5. 复杂系统设计:对于复杂的系统如GUI系统、企业应用程序等,使用中介者模式可以使系统更易于维护和扩展。

5.2 实际应用
  1. 聊天室系统:在一个聊天室应用中,用户之间的消息传递不需要直接相互引用。通过中介者,即聊天室服务器,来协调消息的发送和接收,这样每个用户只需与服务器交互即可。
  2. 微服务架构:在微服务架构中,不同的服务之间通过一个中介者来进行通信,这个中介者通常是服务总线或者消息队列,它负责传递和路由消息,降低了服务间的直接依赖。
  3. 智能家居系统:在智能家居系统中,各种设备如灯光、温度控制器、安全摄像头等,可以通过一个中心控制系统来协调它们的工作,而不是直接相互通信。
  4. 多人游戏:在多人在线游戏中,玩家之间的互动(如聊天、交易、组队等)可以通过一个游戏服务器来中介,这样可以避免玩家之间直接建立连接,减少了系统的复杂性。

6. JDK中的使用

  • java.util.Timer 类
    • 中介者角色(Timer)
      • Timer类提供了注册任务(通过schedule方法)和取消任务的方法,这些方法允许同事类(即需要定时执行的任务)与中介者进行交互。
      • Timer内部维护了一个任务队列,并负责按照指定的时间间隔或延迟来执行这些任务。它协调了各个任务之间的执行顺序和时间,确保它们能够按照预期的方式运行。
    • 同事类角色(TimerTask 或其他实现 Runnable 接口的类)
      • 这些类表示需要定时执行的任务,它们实现了Runnable接口或继承了TimerTask类,并定义了任务的具体执行逻辑。
      • 同事类通过调用Timer类的schedule方法将自己注册到中介者中,并指定执行的时间和周期。一旦注册成功,它们就不再需要直接与其他任务进行交互,而是依赖于Timer中介者来管理和调度它们的执行。

7. 注意事项

  • 避免过度集中控制:虽然中介者有助于降低系统的耦合度,但过度依赖中介者可能导致中介者类的职责过重,增加维护难度。
  • 保持中介者的简洁性:中介者应专注于协调和转发消息,避免在其中引入过多的业务逻辑。
  • 适时重构:随着系统的发展,中介者可能会变得复杂,需要定期审视并重构以保持系统的清晰和可维护性。
  • 性能考量:在某些高性能需求的场景中,中介者可能成为性能瓶颈,需注意性能优化。
  • 扩展性设计:设计时应考虑未来可能的变化,确保中介者模式的实现能够适应新的需求和变化。

8. 中介者模式 VS 组合模式

模式类型目的模式架构主要角色应用场景
中介者模式行为型简化对象间复杂交互,降低耦合度中介者、同事类对象间交互复杂且需要解耦时
组合模式结构型统一处理组合对象与单个对象,表达层次结构组合对象、叶子对象需要表示部分-整体层次结构时

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

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

相关文章

nginx服务访问页面白色

问题描述 访问一个域名服务返回页面空白&#xff0c;非响应404。报错如下图。 排查问题 域名解析正常&#xff0c;网络通讯正常&#xff0c;绕过解析地址访问源站IP地址端口访问正常&#xff0c;nginx无异常报错。 在打开文件时&#xff0c;发现无法打开配置文件&#xff0c…

java 学习一

jdk下载地址 配置环境变量

美国站群服务器如何解决跨国运营中的网络延迟问题?

美国站群服务器如何解决跨国运营中的网络延迟问题? 在当今全球化的商业环境中&#xff0c;跨国企业面临的一个重要挑战是网络延迟问题。网络延迟不仅影响用户体验&#xff0c;还可能导致交易失败或数据传输错误&#xff0c;对企业造成不利影响。然而&#xff0c;利用美国站群…

【机器学习】拉索回归与坐标下降法

实现高效特征选择与模型优化 一、拉索回归的原理与优势二、坐标下降法的实现三、总结与展望 在大数据时代&#xff0c;我们面临着从海量特征中筛选出关键信息&#xff0c;以构建高效预测模型的挑战。拉索回归&#xff08;Lasso Regression&#xff09;作为一种正则化技术&#…

视频滚动字幕一键批量轻松添加,解锁高效字幕编辑,提升视频质量与观众体验

视频已成为我们获取信息、娱乐休闲的重要渠道。一部成功的视频作品&#xff0c;除了画面精美、音质清晰外&#xff0c;字幕的添加也是至关重要的一环。字幕不仅能增强视频的观感&#xff0c;还能提升信息的传达效率&#xff0c;让观众在享受视觉盛宴的同时&#xff0c;更加深入…

怎样快速插入数据

1、30万条数据插入插入数据库验证 1.1、表结构&#xff1a; CREATE TABLE t_user (id int(11) NOT NULL AUTO_INCREMENT COMMENT 用户id,username varchar(64) DEFAULT NULL COMMENT 用户名称,age int(4) DEFAULT NULL COMMENT 年龄,PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT…

相亲平台app小程序

相亲平台app小程序是一种基于手机应用的微型程序&#xff0c;专为在线相亲交友活动设计。它提供了一系列的功能&#xff0c;旨在帮助用户更方便、更高效地找到心仪的伴侣。 首先&#xff0c;用户可以在个人资料部分上传照片、填写个人资料、设置兴趣爱好等信息&#xff0c;以便…

交互式探索微生物群落与生态功能的关系

微生物群落在生态系统中发挥则重要功能&#xff0c;我们在对微生物群落进行分析时&#xff0c;会将不同分类水平&#xff08;从门到属&#xff09;的微生物类群的相对丰度与测定的某一生态功能进行相关性分析。但由于微生物类群数较多&#xff0c;又有不同的分类水平&#xff0…

grafana报错This panel requires Angular (deprecated)

1.原因 报错解释&#xff1a; Grafana在更新到7.0版本后&#xff0c;弃用了AngularJS&#xff08;一种用于构建大型Web应用的JavaScript框架&#xff09;。在早期的Grafana版本中&#xff0c;某些面板可能依赖于AngularJS&#xff0c;但这种依赖已经逐步被新的React或Vue面板所…

使用 Dify 和 Moonshot API 构建你的 AI 工作流(一):让不 AI 的应用 AI 化

有了之前的文章铺垫&#xff0c;这篇文章开始&#xff0c;我们聊聊如何折腾 AI 工作流&#xff0c;把不 AI 的应用&#xff0c;“AI 起来”。 写在前面 上个月&#xff0c;我们聊过了《使用 Dify 和 AWS Bedrock 玩转 Anthropic Claude 3》&#xff0c;里面介绍了如何使用交互…

WPF4 数据模板

数据模板 数据模板常用在3种类型的控件, 下图形式: 1.Grid这种列表表格中修改Cell的数据格式, CellTemplate可以修改单元格的展示数据的方式。 2.针对列表类型的控件, 例如树形控件&#xff0c;下拉列表&#xff0c;列表控件, 可以修改其中的ItemTemplate。 3.修改ContentT…

Linux RTC驱动深入解析

目录标题 实时时钟&#xff08;RTC&#xff09;基础Linux内核中的RTC框架RTC设备类设备树&#xff08;Device Tree&#xff09; 编写Linux RTC驱动1. 初始化和注册2. RTC设备操作函数3. 清理函数 测试RTC驱动驱动开发的挑战总结 在许多嵌入式系统和服务器上&#xff0c;实时时钟…

图像哈希:全局+局部提取特征

文章信息 作者&#xff1a;梁小平&#xff0c;唐振军期刊&#xff1a;ACM Trans. Multimedia Comput. Commun. Appl&#xff08;三区&#xff09;题目&#xff1a;Robust Hashing via Global and Local Invariant Features for Image Copy Detection 目的、实验步骤及结论 目…

STM32的端口引脚的复用功能及重映射功能解析

目录 STM32的端口引脚的复用功能及重映射功能解析 复用功能 复用功能的初始化 重映射功能 重映射功能的初始化 复用功能和重映射的区别 部分重映射与完全重映射 补充 STM32的端口引脚的复用功能及重映射功能解析 复用功能 首先、我们可以这样去理解stm32引脚的复用功能…

SpringBoot学习之Kafka发送消费消息入门实例(三十五)

使用Kafka之前需要先启动fKafka,如何下载安装启动kafka请先参考本篇文章的前两篇: 《SpringBoot学习之Kafka下载安装和启动【Windows版本】(三十四)》 《SpringBoot学习之Kafka下载安装和启动【Mac版本】(三十三)》 一、POM依赖 1、加入kafka依赖 2、我的整个POM代码…

Adobe Photoshop CC 2017无法打开解决方案

Adobe Photoshop CC 2017双击无反应&#xff0c;右键以管理员身份运行也没有反应 解决方案&#xff1a; 事件查看器中查看应用程序的事件 如果找到程序报错事件&#xff0c;网上下载ZXPSignLib-minimal.dll文件替换错误模块路径位置的该文件即可 ZXPSignLib-minimal.dll下载地…

SpringBoot+Vue开发记录(三)

说明&#xff1a;本篇文章的主要内容为需求分析。需求分析这一部分很重要&#xff0c;也稍微有点子难搞&#xff0c;所以本篇文章里的有些内容会有失偏颇。 一、准备步骤 我打算做一个刷题项目&#xff0c;但是具体这个项目该怎么做&#xff0c;我是一头雾水。 所以就要先进行…

pytorch-trainvaltest划分

目录 1. 上一节回顾2. 数据集划分3. 完整代码 1. 上一节回顾 下列图中三种曲线分别代表了欠拟合、好的拟合和过拟合 下图为过拟合曲线&#xff0c;那么如何来检测过拟合呢&#xff1f;将数据集划分为train和val&#xff08;validation&#xff09;val是用来测试训练过程是否过…

CSS 04

去掉 li 前面的 项目符号(小圆点) 语法 list-style: none;圆角边框 border-radius 属性用于设置元素的外边框圆角。 语法 border-radius:length;参数值可以为数值或百分比的形式如果是正方形&#xff0c;想要设置为一个圆&#xff0c;把数值修改为高度或者宽度的一半即可&a…

Opencv_11_通道的分离与合并

void ColorInvert::channels_demo(Mat& image) { std::vector<Mat> mv; split(image, mv); imshow("蓝色", mv[0]); imshow("绿色", mv[1]); imshow("红色", mv[2]); Mat dst; mv[0] 0; merge(mv, dst);…