Java设计模式:中介者模式详解与最佳实践
Java设计模式:中介者模式详解与最佳实践
1. 引言
在软件开发过程中,特别是复杂系统的构建中,模块间的交互往往成为影响代码质量的重要因素。当模块之间耦合度过高时,系统的维护、扩展和理解成本都会显著增加。为了降低模块之间的耦合度,保持系统的灵活性和可维护性,我们可以使用设计模式中的中介者模式(Mediator Pattern)。本篇文章将详细介绍中介者模式的概念、优点及其在Java中的应用,并通过实例代码演示如何实现这一模式。
2. 中介者模式概述
2.1 中介者模式定义
中介者模式是一种行为型设计模式,用于减少多个对象之间的耦合。它通过引入一个中介者对象,使得各个对象不直接相互引用,而是通过中介者对象进行通信。这种模式将对象之间的复杂关系转换为简化的星型关系,从而降低对象之间的耦合度。
2.2 中介者模式的适用场景
中介者模式主要适用于以下场景:
- 对象之间存在复杂的交互关系:如果对象之间的关系错综复杂,直接交互会导致代码难以维护,此时适合引入中介者模式。
- 需要复用对象,但又希望能在不同的上下文中灵活互通:通过中介者模式,可以在不同的中介者中定义不同的交互逻辑。
- 希望将交互行为封装到一个独立的对象中:这样可以更好地控制、管理和扩展交互逻辑,而不影响对象本身的设计。
2.3 中介者模式的优缺点
优点:
- 降低对象之间的耦合:通过中介者对象,各模块不再直接引用彼此,减少了代码的耦合度。
- 集中控制交互逻辑:所有的交互都在中介者中处理,可以统一管理和修改,逻辑集中且清晰。
- 提高代码的可维护性和可扩展性:当新增或修改交互逻辑时,只需更改中介者,减少对原有代码的影响。
缺点:
- 可能导致中介者过于复杂:如果交互逻辑过多,可能导致中介者类变得庞大和复杂,难以维护。
- 降低了对象的独立性:对象过度依赖中介者,可能会使得对象在没有中介者的情况下难以使用。
3. 中介者模式的结构与实现
3.1 中介者模式的结构
中介者模式主要由以下几个角色组成:
- Mediator(中介者):定义了同事对象之间交互的接口。
- ConcreteMediator(具体中介者):实现了中介者接口,协调各个同事对象之间的交互。
- Colleague(同事类):每个同事类只知道自己的行为,不了解其他同事类的情况,它们通过中介者与其他同事类进行通信。
3.2 UML类图
在详细介绍代码实现之前,我们先看一下中介者模式的UML类图:
+------------------+| Mediator |<-------------------++------------------+ || + notify() | |+------------------+ |^ || |+------------------+ || ConcreteMediator | |+------------------+ || + notify() | |+------------------+ |^ || |+------------------+ +------------------+| ColleagueA | | ColleagueB |+------------------+ +------------------+| + send() | | + send() || + receive() | | + receive() |+------------------+ +------------------+
3.3 代码实现
以下是中介者模式的Java代码实现,展示了一个简单的聊天系统,多个用户(同事类)通过中介者进行消息传递。
// 定义中介者接口
interface Mediator {void sendMessage(String message, Colleague colleague);void addColleague(Colleague colleague);
}// 具体中介者类
class ConcreteMediator implements Mediator {private List<Colleague> colleagues;public ConcreteMediator() {this.colleagues = new ArrayList<>();}@Overridepublic void sendMessage(String message, Colleague colleague) {for (Colleague c : colleagues) {// 不发送消息给发送者本身if (c != colleague) {c.receive(message);}}}@Overridepublic void addColleague(Colleague colleague) {colleagues.add(colleague);}
}// 定义同事类的抽象
abstract class Colleague {protected Mediator mediator;public Colleague(Mediator mediator) {this.mediator = mediator;}public abstract void send(String message);public abstract void receive(String message);
}// 具体的同事类:UserA
class UserA extends Colleague {public UserA(Mediator mediator) {super(mediator);}@Overridepublic void send(String message) {System.out.println("UserA发送消息: " + message);mediator.sendMessage(message, this);}@Overridepublic void receive(String message) {System.out.println("UserA收到消息: " + message);}
}// 具体的同事类:UserB
class UserB extends Colleague {public UserB(Mediator mediator) {super(mediator);}@Overridepublic void send(String message) {System.out.println("UserB发送消息: " + message);mediator.sendMessage(message, this);}@Overridepublic void receive(String message) {System.out.println("UserB收到消息: " + message);}
}// 客户端代码
public class MediatorPatternDemo {public static void main(String[] args) {ConcreteMediator mediator = new ConcreteMediator();Colleague userA = new UserA(mediator);Colleague userB = new UserB(mediator);mediator.addColleague(userA);mediator.addColleague(userB);userA.send("你好,UserB!");userB.send("你好,UserA!我收到了你的消息。");}
}
在这个示例中,ConcreteMediator类作为中介者,负责管理Colleague对象之间的消息传递。每个Colleague对象(如UserA和UserB)通过中介者发送和接收消息,而不需要直接引用彼此。
3.4 代码分析
-
松散耦合:
UserA和UserB并不知道对方的存在,它们只通过ConcreteMediator进行通信。这样,如果我们增加一个新的同事类,例如UserC,并不需要修改UserA和UserB的代码,只需要在中介者中处理其交互即可。 -
单一职责原则:每个同事类只负责发送和接收消息,不关心如何传递消息。中介者类集中管理消息的路由逻辑,使得同事类的职责单一化。
-
扩展性:通过中介者模式,可以轻松地增加新的同事类或修改交互逻辑,而不会影响现有的类。
4. 中介者模式的最佳实践
4.1 在大型系统中的应用
在大型系统中,模块之间的交互关系往往非常复杂,使用中介者模式可以有效降低模块间的耦合度。例如,在企业级应用中,用户界面的各个组件之间通常需要频繁交互,使用中介者模式可以使界面组件之间的通信更加清晰和灵活。
4.2 在消息传递系统中的应用
中介者模式非常适合用于消息传递系统中。例如,在即时通讯应用中,各个客户端可以通过服务器(中介者)进行消息传递。服务器负责管理客户端的连接和消息的转发,而客户端只需要关注如何发送和接收消息。
4.3 在微服务架构中的应用
在微服务架构中,各个服务之间的通信往往通过消息队列或事件总线来实现。这种通信方式本质上就是中介者模式的一种应用。通过引入一个消息中介者,可以解耦微服务之间的依赖关系,增强系统的扩展性和容错性。
5. 中介者模式的变体与改进
5.1 事件驱动的中介者模式
在某些情况下,可以结合事件驱动的方式来实现中介者模式。这种变体通常在GUI应用程序或实时系统中
使用,通过事件机制来触发中介者的动作,而不是直接调用方法。
interface EventMediator {void notify(String event, Colleague colleague);
}class EventDrivenMediator implements EventMediator {private Map<String, List<Colleague>> listeners = new HashMap<>();public void subscribe(String event, Colleague colleague) {listeners.putIfAbsent(event, new ArrayList<>());listeners.get(event).add(colleague);}@Overridepublic void notify(String event, Colleague colleague) {if (listeners.containsKey(event)) {for (Colleague c : listeners.get(event)) {if (c != colleague) {c.receive(event + " triggered by " + colleague.getClass().getSimpleName());}}}}
}class EventUserA extends Colleague {public EventUserA(EventMediator mediator) {super(mediator);}public void triggerEvent(String event) {System.out.println("EventUserA triggers event: " + event);mediator.notify(event, this);}@Overridepublic void send(String message) {// Implementation not required for this example}@Overridepublic void receive(String message) {System.out.println("EventUserA received: " + message);}
}class EventUserB extends Colleague {public EventUserB(EventMediator mediator) {super(mediator);}@Overridepublic void send(String message) {// Implementation not required for this example}@Overridepublic void receive(String message) {System.out.println("EventUserB received: " + message);}
}public class EventDrivenMediatorDemo {public static void main(String[] args) {EventDrivenMediator mediator = new EventDrivenMediator();EventUserA userA = new EventUserA(mediator);EventUserB userB = new EventUserB(mediator);mediator.subscribe("event1", userB);userA.triggerEvent("event1");}
}
在这个例子中,中介者模式结合了事件驱动的思想,EventUserA触发了event1事件,EventUserB通过中介者接收到该事件。事件驱动的中介者模式提高了系统的响应性和灵活性。
5.2 中介者模式与观察者模式的结合
中介者模式可以与观察者模式结合使用,通过将观察者模式中的订阅者通知功能整合到中介者中,从而实现更复杂的交互逻辑。这种结合方式特别适用于需要动态管理和通知多个组件的场景。
6. 结论
中介者模式通过引入一个中介者对象,减少了系统中对象之间的直接耦合,从而提高了代码的可维护性和扩展性。在复杂系统的构建中,中介者模式尤其适合处理对象之间复杂的交互关系,避免了代码的混乱和难以维护。
通过本文的详细讲解与代码示例,我们深入理解了中介者模式的核心思想、适用场景以及实际应用中的最佳实践。在实际开发中,掌握并合理运用中介者模式,可以有效提升系统设计的质量,降低维护成本。
相关文章:
Java设计模式:中介者模式详解与最佳实践
Java设计模式:中介者模式详解与最佳实践 1. 引言 在软件开发过程中,特别是复杂系统的构建中,模块间的交互往往成为影响代码质量的重要因素。当模块之间耦合度过高时,系统的维护、扩展和理解成本都会显著增加。为了降低模块之间的…...
Matlab绘制像素风字母颜色及透明度随机变化动画
本文是使用 Matlab 绘制像素风字母颜色及透明度随机变化动画的教程 实现效果 实现代码 如果需要更改为其他字母组合,在下面代码的基础上简单修改就可以使用。 步骤:(1) 定义字母形状;(2) 给出字母组合顺序;(3) 重新运行程序&#…...
C:每日一题:二分查找
1、知识介绍: 1.1 概念: 二分查找是一种在有序数组中查找某一特定元素的搜索算法 1.2 基本思想: 每次将待查找的范围缩小一半,通过比较中间元素与目标元素的大小,来决定是在左半部分还是右半部分继续查找。 举个生…...
python Django中使用ORM进行分组统计并降序排列
python Django中使用ORM进行分组统计并降序排列 # 使用supplier和Count进行分组统计,其中supplier为MyModel的一个字段 supplier_counts MyModel.objects.values(supplier).annotate(countCount(supplier)).order_by(-count) # 输出统计结果 for supplier_count in supplier_…...
QT C++ 编写modbus 总结
[开源库的使用]libModbus编译及使用_libmodbus库-CSDN博客 libmodbus的下载与编译_modbus库文件下载-CSDN博客 【QT5】解决 QT 界面中文显示乱码问题_qt5输出中文乱码解决方法-CSDN博客 Qt:解决qt修改完ui文件起不到作用_qt ui文件修改后不生效-CSDN博客...
基于SpringBoot的网络海鲜市场系统的设计与实现
TOC springboot219基于SpringBoot的网络海鲜市场系统的设计与实现 绪论 1.1 选题背景 当人们发现随着生产规模的不断扩大,人为计算方面才是一个巨大的短板,所以发明了各种计算设备,从结绳记事,到算筹,以及算盘&…...
c#相关基础知识
c#参数4种种别 值参:像Java的正常数据的传输 ref:对参数的指向是参数本身的地址,而不是数据的副本,所以可以对数据进行直接操作 out: 绑定控件,控件传输值赋值给类中的内部类 待定...
注意力机制 — 它是什么以及它是如何工作的
一、说明 注意力机制是深度学习领域的一个突破。它们帮助模型专注于数据的重要部分,并提高语言处理和计算机视觉等任务的理解和性能。这篇文章将深入探讨深度学习中注意力的基础知识,并展示其背后的主要思想。 二、注意力机制回顾 在我们谈论注意力之前&…...
学习嵌入式第二十六天
进程线程 1.进程的概念 2.进程 和 程序 硬盘中程序 ,加载到内存中,运行起来,就是进程 创建线程 pthread_create posix thread create 线程执行 ---体现在线程执行函数 (回调函数) 线程退出 ---pthread_exit() …...
speech语音audio音频
在信号处理和语言技术领域,speech 和 audio 是两个相关但不同的概念。它们有各自的定义和应用场景。以下是对这两个术语的详细解释: 1. Speech(语音) Speech 主要指的是人类说话时产生的声音。它是人类语言交流的一种主要形式&a…...
最常用的正则表达式规则和语法
正则表达式(Regular Expression,简称 regex)是一种用于匹配字符串的强大工具。它使用特定的语法规则来定义字符串模式,可以用来搜索、替换、验证字符串等。以下是一些常用的正则表达式规则和语法: 1. 基本字符匹配 . :匹配任意单个字符(除了换行符)。 示例:a.c 可以匹…...
Datawhale X 魔搭 AI夏令营第四期-魔搭生图task1学习笔记
根据教程提供的链接,进入相应文章了解魔搭生图的主要工作是通过对大量图片的训练,生成自己的模型,然后使用不同的正向、反向提示词使模型输出对应的图片 1.官方跑baseline教程链接:Task 1 从零入门AI生图原理&实践 2.简单列举一下赛事的…...
WPF中XAML相对路径表示方法
在WPF XAML中,相对路径是一种非常实用的方式来引用资源文件,如图像、样式表和其他XAML文件。相对路径可以帮助您构建更加灵活和可移植的应用程序,因为它允许资源文件的位置相对于XAML文件的位置进行定位。 相对路径的表示方法 在XAML中&…...
操作系统内存管理技术详解
操作系统内存管理技术详解:第一部分 引言 操作系统作为计算机系统的核心组件,负责管理硬件资源、提供用户接口和运行应用程序。在操作系统的众多功能中,内存管理无疑是最为关键的技术之一。本文将深入探讨操作系统内存管理的背后技术&…...
python之numpy(2 创建矩阵)
numpy创建矩阵 前面提到,numpy主要是针对数组和矩阵的操作。下面我们分别创建数组和矩阵。 import numpy as np x0np.array([1,2,3,4]) x1np.array([[1,2,3,4],[1,2,3,4]]) print(x0,x1,sep\n) 在numpy中,使用array创建数组和矩阵。其中,创…...
git stage 和 git unstage
无意间遇到 git stage 和 git unstage,感觉有点陌生,简单了解一下这两个概念。 在 Git 中,stage 和 unstage 是与暂存区操作相关的术语,它们用于管理文件的状态,决定哪些更改会在下次的提交中。 1. git stage git s…...
C#使用反射和特性的优缺点
使用反射(Reflection)和特性(Attributes)在C#中有其特定的应用场景,同时也带来了一些优缺点: 反射的优点: 动态性:反射允许程序在运行时查询和操作对象的类型信息,提供…...
C语言:字符串函数strcat
该函数用于字符串拼接。 使用方法如下: #include<stdio.h> #include<string.h>int main() {char str[20] "abcd";char str1[] "1234";//strcat(str,str1);//不安全,所以用strcat_sstrcat_s(str, 20, str1);printf(&…...
haproxy总结与实验
一、负载均衡 1.1 简述负载均衡 在高并发的业务场景下,解决单个节点压力过大,导致Web服务响应过慢,特别是严重的情况下导致服务瘫痪,无法正常提供服务的问题,而负载均衡的目的就是为了维护系统稳定可靠。负载均衡&…...
VS实用调试技巧(程序员的必备技能)
调试的重要性 在我们写代码的时候,如果程序出现了bug,那么下一步就是找到bug并修复bug!而这个找问题的过程就被称为调试(英文叫debug,消灭bug的意思)。 调试能观察到程序内部执行的细节,可以增加程序员对…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
