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

文章目录

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

案例引入

案例一

普通实现

在租房过程中,客户可能去找房东问房子是否可以租,但是房东可能要和家人进行一系列的沟通,最后还可能派出另一个家庭成员来和客户进行交流,整个沟通过程非常复杂、沟通线路繁多。如果是写成程序的模式,不同成员之间需要留好接口方便成员之间互相进行调用

在这里插入图片描述

【分析】

  • 各个成员彼此联系,你中有我,我中有你,不利于松耦合
  • 各个成员之间所传递的消息(参数)容易混乱
  • 当系统增加一个新的成员时,或者执行流程改变时,代码的可维护性、扩展性都不理想

【改进】

  • 使用中介者模式

中介者模式

客户只需要对接中介,其他成员互相之间不进行沟通,由中介来进行沟通。如 屋主—>爸爸 变成 屋主—>中介—>爸爸。通过中介的联络,可以将成员之间的关联关系都搞定
在这里插入图片描述

案例二

现在很多家庭都配备了智能家居,包括各种设备,如闹钟、咖啡机、电视机、窗帘……

当主人想要看电视时,会让多个设备协同工作,来自动完成看电视的准备工作,比如流程为: 闹铃响起->咖啡机开始做咖啡->窗帘自动落下->电视机开始播放

介绍

基础介绍

  • 在中介者模式中,团队组员之间不再互相沟通并私自做出决定,而是发生任何事情都向中介者报告,中介者站在整个团队的角度上对组员上报的事情做出决定。当中介者下达指示时,组员会立即执行
  • 用一个中介对象来封装一系列的对象交互方法。中介者使各个对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互
  • 中介者模式属于行为型模式
  • 在MVC模式中,C(Controller控制器) 是M(Model模型) 和V(View视图)的中介者,在前后端交互时起到了中间人的作用

在这里插入图片描述

登场角色

尚硅谷

在这里插入图片描述

  • Mediator 就是抽象中介者,定义了同事对象到中介者对象的接口
  • Colleague 是抽象同事类
  • ConcreteMediator 具体的中介者对象,实现抽象方法,他需要知道所有的具体同事类,即以HashMap管理所有同事类,并接受某个同事对象的消息,来协调其他同事完成相应的任务
  • ConcreteColleague 具体的同事类,可能会有很多个,每个同事只知道自己的行为,而不了解其他同事类的行为(方法),他们都依赖中介者对象

《图解设计模式》

在这里插入图片描述

  • Mediator(仲裁者、中介者):负责定义与 Colleague 角色进行通信和做出决定的接口(API)
  • ConcreteMediator(具体的仲裁者、中介者):负责实现 Mediator 角色的接口(API),负责实际上如何做出决定
  • Colleague(同事):负责定义与Mediator角色进行通信的接口(API)
  • ConcreteColleague(具体的同事):负责实现 Colleague 角色的接口(API)

案例实现

案例一:智能家庭

类图

在这里插入图片描述

【操作流程】

  • 创建 ConcreteMediator 对象
  • 创建各个同事类对象,比如: Alarm、CoffeeMachine、TV
  • 在创建同事类对象的时候,就直接通过构造器,加入到 colleagueMap
  • 同事类对象,可以调用sendMessage,最终会去调用ConcreteMediator的getMessage方法
  • getMessage(核心方法)会根据接收到的同事对象发出的消息 来协调调用其它的同事对象来共同完成任务

实现

【抽象中介者类】

package com.atguigu.mediator.smarthouse;public abstract class Mediator {/*** 将给中介者对象,加入到集合中* @param colleagueName* @param colleague*/public abstract void register(String colleagueName, Colleague colleague);/*** 接收消息, 具体的同事对象发出* @param stateChange* @param colleagueName*/public abstract void getMessage(int stateChange, String colleagueName);public abstract void sendMessage();
}

【具体中介者类】

package com.atguigu.mediator.smarthouse;import java.util.HashMap;/*** 具体的中介者类*/
public class ConcreteMediator extends Mediator {/*** 集合,放入所有的同事对象*/private HashMap<String, Colleague> colleagueMap;private HashMap<String, String> interMap;public ConcreteMediator() {colleagueMap = new HashMap<String, Colleague>();interMap = new HashMap<String, String>();}@Overridepublic void register(String colleagueName, Colleague colleague) {colleagueMap.put(colleagueName, colleague);if (colleague instanceof Alarm) {interMap.put("Alarm", colleagueName);} else if (colleague instanceof CoffeeMachine) {interMap.put("CoffeeMachine", colleagueName);} else if (colleague instanceof TV) {interMap.put("TV", colleagueName);} else if (colleague instanceof Curtains) {interMap.put("Curtains", colleagueName);}}/*** 具体中介者的核心方法* 1. 根据得到消息,完成对应任务* 2. 中介者在这个方法,协调各个具体的同事对象,完成任务* @param stateChange* @param colleagueName*/@Overridepublic void getMessage(int stateChange, String colleagueName) {//处理闹钟发出的消息if (colleagueMap.get(colleagueName) instanceof Alarm) {if (stateChange == 0) {// 老司机做咖啡((CoffeeMachine) (colleagueMap.get(interMap.get("CoffeeMachine")))).StartCoffee();// 启动电视((TV) (colleagueMap.get(interMap.get("TV")))).StartTv();} else if (stateChange == 1) {// 关掉电视((TV) (colleagueMap.get(interMap.get("TV")))).StopTv();}} else if (colleagueMap.get(colleagueName) instanceof CoffeeMachine) {// 将窗帘升起来((Curtains) (colleagueMap.get(interMap.get("Curtains")))).UpCurtains();} else if (colleagueMap.get(colleagueName) instanceof TV) {//如果TV发现消息} else if (colleagueMap.get(colleagueName) instanceof Curtains) {//如果是以窗帘发出的消息,这里处理...}}@Overridepublic void sendMessage() {}}

【抽象同事类:Colleague】

package com.atguigu.mediator.smarthouse;/*** 抽象同事类*/
public abstract class Colleague {/*** 关联 Mediator*/private Mediator mediator;public String name;public Colleague(Mediator mediator, String name) {this.mediator = mediator;this.name = name;}public Mediator GetMediator() {return this.mediator;}public abstract void SendMessage(int stateChange);
}

【具体同事类:闹钟】

package com.atguigu.mediator.smarthouse;/*** 具体的同事类 闹钟*/
public class Alarm extends Colleague {/*** 构造器* @param mediator* @param name*/public Alarm(Mediator mediator, String name) {super(mediator, name);//在创建Alarm 同事对象时,将自己放入到ConcreteMediator 对象的集合中mediator.register(name, this);}public void SendAlarm(int stateChange) {SendMessage(stateChange);}@Overridepublic void SendMessage(int stateChange) {//调用的中介者对象的getMessagethis.GetMediator().getMessage(stateChange, this.name);}}

【具体同事类:窗帘】

package com.atguigu.mediator.smarthouse;/*** 窗帘*/
public class Curtains extends Colleague {public Curtains(Mediator mediator, String name) {super(mediator, name);mediator.register(name, this);}@Overridepublic void SendMessage(int stateChange) {this.GetMediator().getMessage(stateChange, this.name);}public void UpCurtains() {System.out.println("I am holding Up Curtains!");}}

【具体同事类:电视】

package com.atguigu.mediator.smarthouse;public class TV extends Colleague {public TV(Mediator mediator, String name) {super(mediator, name);mediator.register(name, this);}@Overridepublic void SendMessage(int stateChange) {this.GetMediator().getMessage(stateChange, this.name);}public void StartTv() {System.out.println("It's time to StartTv!");}public void StopTv() {System.out.println("StopTv!");}
}

【主类】

package com.atguigu.mediator.smarthouse;public class ClientTest {public static void main(String[] args) {//创建一个中介者对象Mediator mediator = new ConcreteMediator();//创建Alarm并且加入到 ConcreteMediator 对象的HashMapAlarm alarm = new Alarm(mediator, "alarm");//创建了CoffeeMachine对象,并且加入到 ConcreteMediator 对象的HashMapCoffeeMachine coffeeMachine = new CoffeeMachine(mediator,"coffeeMachine");//创建 Curtains, 并且加入到 ConcreteMediator 对象的HashMapCurtains curtains = new Curtains(mediator, "curtains");TV tV = new TV(mediator, "TV");//让闹钟发出消息alarm.SendAlarm(0);//做好咖啡coffeeMachine.FinishCoffee();alarm.SendAlarm(1);}}

【运行】

It's time to startcoffee!
It's time to StartTv!
After 5 minutes!
Coffee is ok!
I am holding Up Curtains!
StopTv!Process finished with exit code 0

【分析】

  • 程序拓展性较好:如果添加一个机器,只需要添加一个 ConcreteColleague 并修改 ConcreteMediator 的相关方法就行,客户端不用改变

案例二:登录页面逻辑实现

说明

在这里插入图片描述

需要实现一个系统登录表单功能,具体的处理逻辑如下:

  • 如果选择作为游客访问,那么禁用用户名输入框和密码输入框,使用户无法输入
  • 如果选择作为用户登录,那么启用用户名输入框和密码输入框,使用户可以输入
  • 如果在用户名输入框中一个字符都没有输入,那么禁用密码输入框,使用户无法输入密码
  • 如果在用户名输入框中输入了至少一个字符,那么启用密码输入框,使用户可以输入密码(当然,如果选择作为游客访问,那么密码框依然是禁用状态 )
  • 只有当用户名输入框和密码输入框中都至少输入一个字符后,OK 按钮才处于启用状态,可以被按下
  • 用户名输入框或密码输入框中一个字符都没有被输入的时候,禁用OK按钮,使其不可被按下(当然,如果选择作为游客访问,那么OK 按总是处于启用状态)
  • Cancel按钮总是处于启用状态,任何时候都可以按下该按钮

类图

在这里插入图片描述

实现

中介者接口和组员接口的方法并非固定就是这些,当中介者和组员需要其他合作的话,就需要定义更多的方法

【中介者接口】

package com.atguigu.mediator.Sample;public interface Mediator {/*** 生成 Mediator 管理的组员*/public abstract void createColleagues();/*** 每个组员都会调用这个方法来向中介者汇报*/public abstract void colleagueChanged();
}

【组员接口】

package com.atguigu.mediator.Sample;public interface Colleague {/*** 设置中介者,告诉组员中介者是谁** @param mediator*/public abstract void setMediator(Mediator mediator);/*** 告知组员中介者所下达的指令* @param enabled 控制是否启用组员的功能*/public abstract void setColleagueEnabled(boolean enabled);
}

【组员:按钮】

package com.atguigu.mediator.Sample;import java.awt.*;public class ColleagueButton extends Button implements Colleague {private Mediator mediator;public ColleagueButton(String caption) {super(caption);}public void setMediator(Mediator mediator) {// 保存Mediatorthis.mediator = mediator;}public void setColleagueEnabled(boolean enabled) {// Mediator下达启用/禁用的指示// setEnabled是java.awt.Button定义的方法,用来控制按钮组件是启用还是禁用,当设置为false时,按钮无法被按下setEnabled(enabled);}
}

【组员:文本输入框】

package com.atguigu.mediator.Sample;import java.awt.*;
import java.awt.event.TextEvent;
import java.awt.event.TextListener;/*** 实现 TextListener 接口来实现监听事件*/
public class ColleagueTextField extends TextField implements TextListener, Colleague {private Mediator mediator;public ColleagueTextField(String text, int columns) {   // 构造函数super(text, columns);}public void setMediator(Mediator mediator) {            // 保存Mediatorthis.mediator = mediator;}public void setColleagueEnabled(boolean enabled) {      // Mediator下达启用/禁用的指示setEnabled(enabled);// 控件启用时,背景色变成白色;否则变为灰色setBackground(enabled ? Color.white : Color.lightGray);}/*** TextListener 中定义的方法,监听文本内容的变化,并通知中介者* @param e*/public void textValueChanged(TextEvent e) {// 当文字发生变化时通知Mediatormediator.colleagueChanged();}
}

【组员:单选按钮】

package com.atguigu.mediator.Sample;import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;/*** 单选按钮*/
public class ColleagueCheckbox extends Checkbox implements ItemListener, Colleague {private Mediator mediator;public ColleagueCheckbox(String caption, CheckboxGroup group, boolean state) {// 构造函数super(caption, group, state);}public void setMediator(Mediator mediator) {// 保存Mediatorthis.mediator = mediator;}public void setColleagueEnabled(boolean enabled) {// Mediator下达启用/禁用指示setEnabled(enabled);}/*** 监听单选按钮的状态变化* @param e*/public void itemStateChanged(ItemEvent e) {// 当状态发生变化时通知Mediatormediator.colleagueChanged();}
}

【具体中介者】

package com.atguigu.mediator.Sample;import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;/*** 具体中介者*/
public class LoginFrame extends Frame implements ActionListener, Mediator {private ColleagueCheckbox checkGuest;private ColleagueCheckbox checkLogin;private ColleagueTextField textUser;private ColleagueTextField textPass;private ColleagueButton buttonOk;private ColleagueButton buttonCancel;/*** 构造函数* 生成并配置各个Colleague后,显示对话框** @param title*/public LoginFrame(String title) {super(title);// 设置登录对话框的背景颜色setBackground(Color.lightGray);// 使用布局管理器生成4×2窗格setLayout(new GridLayout(4, 2));// 生成各个 ColleaguecreateColleagues();// 配置 Colleagueadd(checkGuest);add(checkLogin);add(new Label("Username:"));add(textUser);add(new Label("Password:"));add(textPass);add(buttonOk);add(buttonCancel);// 设置初始的启用起用/禁用状态colleagueChanged();// 显示pack();show();}/*** 生成登录对话框所需要的各个Colleague*/public void createColleagues() {// 生成CheckboxGroup g = new CheckboxGroup();checkGuest = new ColleagueCheckbox("Guest", g, true);checkLogin = new ColleagueCheckbox("Login", g, false);textUser = new ColleagueTextField("", 10);textPass = new ColleagueTextField("", 10);textPass.setEchoChar('*');buttonOk = new ColleagueButton("OK");buttonCancel = new ColleagueButton("Cancel");// 设置MediatorcheckGuest.setMediator(this);checkLogin.setMediator(this);textUser.setMediator(this);textPass.setMediator(this);buttonOk.setMediator(this);buttonCancel.setMediator(this);// 设置ListenercheckGuest.addItemListener(checkGuest);checkLogin.addItemListener(checkLogin);textUser.addTextListener(textUser);textPass.addTextListener(textPass);buttonOk.addActionListener(this);buttonCancel.addActionListener(this);}/*** 控制各个成员的状态* 接收来自于 Colleague 的通知,然后判断各 Colleague 的启用/禁用状态* * 单选按钮的选中状态发生改变 或者 文本输入框的内容发生改变,都会调用这个方法*/public void colleagueChanged() {// checkGuest.getState()获取游客模式的按钮是否处于选中状态if (checkGuest.getState()) {// 游客模式textUser.setColleagueEnabled(false);textPass.setColleagueEnabled(false);buttonOk.setColleagueEnabled(true);} else {// 登录模式textUser.setColleagueEnabled(true);userpassChanged();}}/*** 当textUser或是textPass文本输入框中的文字发生变化时* 判断各Colleage的启用/禁用状态*/private void userpassChanged() {if (textUser.getText().length() > 0) {textPass.setColleagueEnabled(true);if (textPass.getText().length() > 0) {buttonOk.setColleagueEnabled(true);} else {buttonOk.setColleagueEnabled(false);}} else {textPass.setColleagueEnabled(false);buttonOk.setColleagueEnabled(false);}}public void actionPerformed(ActionEvent e) {System.out.println(e.toString());System.exit(0);}
}

【主类】

package com.atguigu.mediator.Sample;public class Main {static public void main(String args[]) {new LoginFrame("Mediator Sample");}
}

【运行】

在这里插入图片描述

总结

【优点】

  • 多个类相互耦合,会形成网状结构(通信路线很多),使用中介者模式将网状结构分离为星型结构进行解耦
  • 减少类间依赖,峰低了耦合,符合迪米特原则
  • 如果出现了Bug,比较容易定位Bug的位置
  • ConcreteColleague容易复用(如果需要写一个新的对话框,那么按钮、文本输入框都可以很容易使用到新的对话框中)

【缺点】

  • 中介者承担了较多的责任,一旦中介者出现了问题,整个系统就会受到影响
  • 如果设计不当,中介者对象本身变得过于复杂,这点在实际使用时,要特别注意
  • ConcreteMediator难以复用,因为其依赖于特定的应用程序

文章说明

  • 本文章为本人学习尚硅谷的学习笔记,文章中大部分内容来源于尚硅谷视频(点击学习尚硅谷相关课程),也有部分内容来自于自己的思考,发布文章是想帮助其他学习的人更方便地整理自己的笔记或者直接通过文章学习相关知识,如有侵权请联系删除,最后对尚硅谷的优质课程表示感谢。
  • 本人还同步阅读《图解设计模式》书籍(图解设计模式/(日)结城浩著;杨文轩译–北京:人民邮电出版社,2017.1),进而综合两者的内容,让知识点更加全面

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode[164]最大间距

难度&#xff1a;Hard 题目&#xff1a; 给定一个无序的数组 nums&#xff0c;返回 数组在排序之后&#xff0c;相邻元素之间最大的差值 。如果数组元素个数小于 2&#xff0c;则返回 0 。 您必须编写一个在「线性时间」内运行并使用「线性额外空间」的算法。 示例 1: 输入: …

中心极限定理例题

关于大数定律的两个题目。 例1 注意牢记公式&#xff1a; P { X } P { ∑ i 1 n x i − n μ n σ < x } ∫ − ∞ x e − x 2 2 d x 2 π P\{ X\} P \{\frac { \sum_{i1}^{n} x_i - n \mu}{\sqrt {n} \sigma} < x \} \frac {\int _{-\infty} ^{x} e ^{- \frac {x^…

【Freertos基础入门】freertos任务的优先级

文章目录 前言一、任务优先级1.Tick2.修改任务优先级 总结 前言 本系列基于stm32系列单片机来使用freerots 任务管理是实时操作系统&#xff08;RTOS&#xff09;的核心功能之一&#xff0c;它允许开发者以并发的方式组织和管理多个任务。FreeRTOS 是一个流行的开源RTOS&…

使用JavaScript实现页面滑动切换效果

使用JavaScript实现页面滑动切换效果 在现代Web页面设计中&#xff0c;页面滑动切换效果已经成为了一种常见的设计要求&#xff0c;能够提升用户体验&#xff0c;增加页面的交互性。本文将通过JavaScript来实现这一效果。 首先&#xff0c;我们需要在HTML中添加一些基础结构和…

进销存管理系统(小杨国贸)springboot采购仓库财务java jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 进销存管理系统&#xff08;小杨国贸&#xff09;spri…

openGauss学习笔记-37 openGauss 高级数据管理-事务

文章目录 openGauss学习笔记-37 openGauss 高级数据管理-事务37.1 语法格式37.2 参数说明37.3 示例 openGauss学习笔记-37 openGauss 高级数据管理-事务 事务是用户定义的一个数据库操作序列&#xff0c;这些操作要么全做要么全不做&#xff0c;是一个不可分割的工作单位。ope…

【积水成渊】9 个CSS 伪元素

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人_python人工智能视觉&#xff08;opencv&#xff09;从入门到实战,前端,微信小程序-CSDN博客 最新的uniapp毕业设计专栏也放在下方了&#xff1a; https://blog.csdn.net/lbcy…

利用三维内容编辑器制作VR交互课件,简单好用易上手

随着虚拟现实技术的不断发展&#xff0c;越来越多的教育机构开始尝试将其应用于教育教学中。然而&#xff0c;要实现这一目标并不容易&#xff0c;需要专业的技术支持和开发团队。 为了解决这一问题&#xff0c;广州华锐互动研发了三维内容编辑器&#xff0c;它是一种基于虚拟现…

Linux 发行版 Debian 12.1 发布

导读在今年 6 月初&#xff0c;Debian 12“bookworm”发布&#xff0c;而日前 Debian 迎来了 12.1 版本&#xff0c;主要修复系统用户创建等多个安全问题。 Debian 是最古老的 GNU / Linux 发行版之一&#xff0c;也是许多其他基于 Linux 的操作系统的基础&#xff0c;包括 Ub…

指针进阶大冒险:解锁C语言中的奇妙世界!

目录 引言 第一阶段&#xff1a;&#x1f50d; 独特的字符指针 什么是字符指针&#xff1f; 字符指针的用途 演示&#xff1a;使用字符指针拷贝字符串 字符指针与字符串常量 小试牛刀 第二阶段&#xff1a;&#x1f3af; 玩转指针数组 指针数组是什么&#xff1f; 指针…

【Fegin技术专题】「原生态」打开Fegin之RPC技术的开端,你会使用原生态的Fegin吗?(中)

你可以使用 Jersey 和 CXF 这些来写一个 Rest 或 SOAP 服务的java客服端。 你也可以直接使用 Apache HttpClient 来实现。但是 Feign 的目的是尽量的减少资源和代码来实现和 HTTP API 的连接。 *通过自定义的编码解码器以及错误处理&#xff0c;你可以编写任何基于文本的 HTT…

Android OkHttp源码分析--分发器

OkHttp是当下Android使用最频繁的网络请求框架&#xff0c;由Square公司开源。Google在Android4.4以后开始将源码中 的HttpURLConnection底层实现替换为OKHttp&#xff0c;同时现在流行的Retrofit框架底层同样是使用OKHttp的。 OKHttp优点: 1、支持Http1、Http2、Quic以及Web…