设计模式-行为型模式之中介者模式

news/2024/4/25 0:03:20/

2. 中介者模式

2.1. 模式动机

在用户与用户直接聊天的设计方案中,用户对象之间存在很强的 关联性,将导致系统出现如下问题:
  • 系统结构复杂

对象之间存在大量的相互关联和调用,若有一个对象发生变化,则需要跟踪和该对象关联的其他所有对象,并进行适当处理。
  • 对象可重用性差

由于一个对象和其他对象具有很强的关联,若没有其他对象的支持,一个对象很难被另一个系统或模块重用,这些对象表现出来更像一个不可分割的整体,职责较为混乱。
  • 系统扩展性低

增加一个新的对象需要在原有相关对象上增加引用,增加新的引用关系也需要调整原有对象,系统耦合度很高,对象操作很不灵活,扩展性差。
在面向对象的软件设计与开发过程中,根据“单一职责原则”,我们应该尽量将对象细化,使其只负责或呈现单一的职责。
对于一个模块,可能由很多对象构成,而且这些对象之间可能存在相互的引用,为了减少对象两两之间复杂的引用关系,使之成为一个松耦合的系统,我们需要使用中介者模式,这就是中介者模式的模式动机。

2.2. 模式定义

中介者模式(Mediator Pattern)定义:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式

2.3. 模式结构

中介者模式包含如下角色:

  • Mediator: 抽象中介者

  • ConcreteMediator: 具体中介者

  • Colleague: 抽象同事类

  • ConcreteColleague: 具体同事类

2.4. 时序图

2.5. 代码分析

#include <iostream>
#include "ConcreteColleagueA.h"
#include "ConcreteMediator.h"
#include "ConcreteColleagueB.h"using namespace std;int main(int argc, char *argv[])
{ConcreteColleagueA * pa = new ConcreteColleagueA();ConcreteColleagueB * pb = new ConcreteColleagueB();ConcreteMediator * pm = new ConcreteMediator();pm->registered(1,pa);pm->registered(2,pb);// sendmsg from a to bpa->sendmsg(2,"hello,i am a");// sendmsg from b to apb->sendmsg(1,"hello,i am b");delete pa,pb,pm;return 0;
}
///
//  ConcreteMediator.h
//  Implementation of the Class ConcreteMediator
//  Created on:      07-十月-2014 21:30:47
//  Original author: colin
///#if !defined(EA_8CECE546_61DD_456f_A3E7_D98BC078D8E8__INCLUDED_)
#define EA_8CECE546_61DD_456f_A3E7_D98BC078D8E8__INCLUDED_#include "ConcreteColleagueB.h"
#include "Mediator.h"
#include "ConcreteColleagueA.h"
#include <map>
using namespace std;
class ConcreteMediator : public Mediator
{public:ConcreteMediator();virtual ~ConcreteMediator();virtual void operation(int nWho,string str);virtual void registered(int nWho, Colleague * aColleague);
private:map<int,Colleague*> m_mpColleague;
};
#endif // !defined(EA_8CECE546_61DD_456f_A3E7_D98BC078D8E8__INCLUDED_)
///
//  ConcreteMediator.cpp
//  Implementation of the Class ConcreteMediator
//  Created on:      07-十月-2014 21:30:48
//  Original author: colin
///#include "ConcreteMediator.h"
#include <map>
#include <iostream>
using namespace std;ConcreteMediator::ConcreteMediator(){}ConcreteMediator::~ConcreteMediator(){}void ConcreteMediator::operation(int nWho,string str){map<int,Colleague*>::const_iterator itr = m_mpColleague.find(nWho);if(itr == m_mpColleague.end()){cout << "not found this colleague!" << endl;return;}Colleague* pc = itr->second;pc->receivemsg(str);
}void ConcreteMediator::registered(int nWho,Colleague * aColleague){map<int,Colleague*>::const_iterator itr = m_mpColleague.find(nWho);if(itr == m_mpColleague.end()){m_mpColleague.insert(make_pair(nWho,aColleague));//同时将中介类暴露给colleague aColleague->setMediator(this);}
}
///
//  ConcreteColleagueA.h
//  Implementation of the Class ConcreteColleagueA
//  Created on:      07-十月-2014 21:30:47
//  Original author: colin
///#if !defined(EA_79979DD4_1E73_46db_A635_E3F516ACCE0A__INCLUDED_)
#define EA_79979DD4_1E73_46db_A635_E3F516ACCE0A__INCLUDED_#include "Colleague.h"class ConcreteColleagueA : public Colleague
{public:ConcreteColleagueA();virtual ~ConcreteColleagueA();virtual void sendmsg(int toWho,string str);virtual void receivemsg(string str);};
#endif // !defined(EA_79979DD4_1E73_46db_A635_E3F516ACCE0A__INCLUDED_)
///
//  ConcreteColleagueA.cpp
//  Implementation of the Class ConcreteColleagueA
//  Created on:      07-十月-2014 21:30:47
//  Original author: colin
///#include "ConcreteColleagueA.h"
#include <iostream>
using namespace std;ConcreteColleagueA::ConcreteColleagueA(){
}ConcreteColleagueA::~ConcreteColleagueA(){
}void ConcreteColleagueA::sendmsg(int toWho,string str){cout << "send msg from colleagueA,to:" << toWho << endl;m_pMediator->operation(toWho,str);
}void ConcreteColleagueA::receivemsg(string str){cout << "ConcreteColleagueA reveivemsg:" << str <<endl;
}

运行结果:

2.6. 模式分析

中介者模式可以使对象之间的关系数量急剧减少。

中介者承担两方面的职责:

  • 中转作用(结构性)

通过中介者提供的中转作用,各个同事对象就不再需要显式引用其他同事,当需要和其他同事进行通信时,通过中介者即可。该中转作用属于中介者在结构上的支持。
  • 协调作用(行为性)

中介者可以更进一步的对同事之间的关系进行封装,同事可以一致地和中介者进行交互,而不需要指明中介者需要具体怎么做,中介者根据封装在自身内部的协调逻辑,对同事的请求进行进一步处理,将同事成员之间的关系行为进行分离和封装。该协调作用属于中介者在行为上的支持。

时序图

2.7. 实例

实例:虚拟聊天室

某论坛系统欲增加一个虚拟聊天室,允许论坛会员通过该聊天室进行信息交流,普通会员(CommonMember)可以给其他会员发送文本信息,钻石会员(DiamondMember)既可以给其他会员发送文本信息,还可以发送图片信息。该聊天室可以对不雅字符进行过滤,如“日”等字符;还可以对发送的图片大小进行控制。用中介者模式设计该虚拟聊天室。

2.8. 优点

中介者模式的优点

  • 简化了对象之间的交互。

  • 将各同事解耦。

  • 减少子类生成。

  • 可以简化各同事类的设计和实现。

2.9. 缺点

中介者模式的缺点

  • 在具体中介者类中包含了同事之间的交互细节,可能会导致具体中介者类非常复杂,使得系统难以维护。

2.10. 适用环境

在以下情况下可以使用中介者模式:

  • 系统中对象之间存在复杂的引用关系,产生的相互依赖关系结构混乱且难以理解。

  • 一个对象由于引用了其他很多对象并且直接和这些对象通信,导致难以复用该对象。

  • 想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。可以通过引入中介者类来实现,在中介者中定义对象。

  • 交互的公共行为,如果需要改变行为则可以增加新的中介者类。

2.11. 模式应用

MVC架构中控制器

Controller 作为一种中介者,它负责控制视图对象View和模型对象Model之间的交互。如在Struts中,Action就可以作为JSP页面与业务对象之间的中介者。

2.12. 模式扩展

中介者模式迪米特法则

  • 在中介者模式中,通过创造出一个中介者对象,将系统中有关的对象所引用的其他对象数目减少到最少,使得一个对象与其同事之间的相互作用被这个对象与中介者对象之间的相互作用所取代。因此,中介者模式就是迪米特法则的一个典型应用

中介者模式GUI开发

  • 中介者模式可以方便地应用于图形界面(GUI)开发中,在比较复杂的界面中可能存在多个界面组件之间的交互关系。

  • 对于这些复杂的交互关系,有时候我们可以引入一个中介者类,将这些交互的组件作为具体的同事类,将它们之间的引用和控制关系交由中介者负责,在一定程度上简化系统的交互,这也是中介者模式的常见应用之一。

2.13. 总结

  • 中介者模式用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式

  • 中介者模式包含四个角色抽象中介者用于定义一个接口,该接口用于与各同事对象之间的通信;具体中介者是抽象中介者的子类,通过协调各个同事对象来实现协作行为,了解并维护它的各个同事对象的引用;抽象同事类定义各同事的公有方法;具体同事类是抽象同事类的子类,每一个同事对象都引用一个中介者对象;每一个同事对象在需要和其他同事对象通信时,先与中介者通信,通过中介者来间接完成与其他同事类的通信;在具体同事类中实现了在抽象同事类中定义的方法。

  • 通过引入中介者对象,可以将系统的网状结构变成以中介者为中心的星形结构,中介者承担了中转作用协调作用中介者类是中介者模式的核心,它对整个系统进行控制和协调,简化了对象之间的交互,还可以对对象间的交互进行进一步的控制。

  • 中介者模式的主要优点在于简化了对象之间的交互,将各同事解耦,还可以减少子类生成,对于复杂的对象之间的交互,通过引入中介者,可以简化各同事类的设计和实现;中介者模式主要缺点在于具体中介者类中包含了同事之间的交互细节,可能会导致具体中介者类非常复杂,使得系统难以维护

  • 中介者模式适用情况包括:系统中对象之间存在复杂的引用关系,产生的相互依赖关系结构混乱且难以理解;一个对象由于引用了其他很多对象并且直接和这些对象通信,导致难以复用该对象;想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。

[上一节]设计模式-行为型模式之命令模式

[下一节]设计模式-行为型模式之观察者模式


http://www.ppmy.cn/news/48145.html

相关文章

苹果撤离中国市场?中国市场太重要,印度制造是备胎

苹果在中国之行后&#xff0c;却计划进一步扩大印度制造iPhone的比例&#xff0c;甚至将iPhone15全数交给印度制造&#xff0c;业界因此认为苹果正在离开中国市场&#xff0c;然而这完全是臆想&#xff0c;中国市场对苹果来说仍然非常重要&#xff0c;它不会轻易舍弃这个市场。…

进程和线程的区别

进程和线程的区别 进程线程线程和进程的区别堆栈空间安全性通信机制 什么时候使用进程和线程线程和进程之间的关系多线程一般用在哪些方面多线程的优点多线程的缺点 进程 资源分配的最小单元 线程 程序执行的最小单元 系统分配处理器时间的基本单元 线程和进程的区别 堆栈…

( “树” 之 BFS) 637. 二叉树的层平均值 ——【Leetcode每日一题】

637. 二叉树的层平均值 给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 1 0 − 5 10^{-5} 10−5 以内的答案可以被接受。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[3.00000,14.50000,1…

性能优化3-分帧寻路+寻路任务统一管理

前言 当项目里的地图越来越大&#xff0c;一些性能上的问题开始逐渐出现&#xff0c;比如寻路。玩家在操控角色移动的时候&#xff0c;指引需要实时更新&#xff0c;同时一些npc也需要做移动&#xff0c;容易出现cpu占用率短时间过高&#xff0c;甚至掉帧的情况。 去年底的时候…

java基于mvc的停车收费系统mysql

系统需要解决的主要问题有&#xff1a; (1)车位管理模块 添加车位、查看车位状态、车位信息查询等。 (2)客户信息管理模块 客户基本信息录入、客户信息查询等。 (3)卡业务办理 添加卡信息、查余额查询、卡充值。 (4)车辆信息管理模块 车牌信息录入等。 (5)收费管理 可以调整相应…

<a> 元素相关属性及方法

<a> 元素 <a>元素用来设置链接。除了网页元素的通用接口&#xff08;Node接口、Element接口、HTMLElement接口&#xff09;&#xff0c;它还继承了HTMLAnchorElement接口和HTMLHyperlinkElementUtils接口。 目录 属性 URL 相关属性accessKey 属性download 属性href…

linux及openEuler破解root密码

第一步&#xff1a;开机的时候按键盘的字母 E 键&#xff0c; 进入引导模式 第二步&#xff1a;进入引导模式 &#xff1a;找到linux这一行&#xff0c;按键盘上的end 键&#xff0c;跳转到行尾&#xff0c;输入&#xff1a; init/bin/sh 修改完后&#xff0c;按键盘上的 ctr…

上海车展:比亚迪宋L概念车全球首发,这是要硬扛特斯拉?

纵观2023年的新能源汽车市场&#xff0c;特斯拉可以说当仁不让地成为了全球最为“吸睛”的车企之一。凭借一系列令无数人瞠目结舌的降价举措&#xff0c;特斯拉给全球汽车市场带来了强烈冲击。虽然特斯拉上海工厂已经接近满负荷运转&#xff0c;但是面对雪片般飞来的订单依然供…

python学习——缺失值、重复值处理、排序及替换

文章目录 1 缺失值处理1.1 查看缺失值 df.isnull()1.2 统计缺失值 df.isnull().sum()1.3 删除缺失值 df.drop()1.4 填充缺失值 df.fillna()1.4.1 固定值填充 df.fillna(value)1.4.2 线性插值填充 df.fillna(df.interpolate()) 2 重复值处理2.1 查看重复值 df.duplicated()2.2 筛…

docker简单教程(三)常用操作

docker简单教程&#xff08;三&#xff09;常用操作 文章目录 docker简单教程&#xff08;三&#xff09;常用操作1&#xff1a;查看所有容器列表&#xff1a;docker ps -a2&#xff1a;查看正在运行的容器列表&#xff1a;docker ps3&#xff1a;运行容器&#xff1a;docker r…

测牛学堂:2023软件测试linux和shell脚本入门系列(shell的运算符)

shell中的注释 以# 开头的就是shell中的注释&#xff0c;不会被执行&#xff0c;是给编程的人看的。 shell中的运算符 shell中有很多运算符。 按照分类&#xff0c;可以分为算术运算符&#xff0c;关系运算符&#xff0c;布尔运算符&#xff0c;字符串运算符&#xff0c;文件…

把树莓派改造成无线软路由器(2)-----无线路由器模式(独立无线路由器)

本文目录 1、准备工作2、安装无线AP和管理软件3、设置网络路由3.1、树莓派的无线网络接口IP配置3.2、启用路由和IP伪装3.3、为无线网络配置DHCP和DNS服务 4、确认无线配置5、配置 AP 软件6、运行wifi无线AP 树莓派可用作网络中的一个wifi无线路由器。让使用无线接入的计算机和设…

sqlserver用SQL脚本进行备份和还原操作

--1.1备份数据库脚本 USE [master] GO BACKUP DATABASE [Test] TO DISK D:\Test\Test_20230419.bak GO --1.2还原数据库,注意一定要用NORECOVERY还原备份 USE [master] GO RESTORE DATABASE [Test] FROM DISKND:\Test\Test_20230419.bak WITH FILE 1, MOVE NTest TO ND:\Test…

后缀数组的应用:最长公共子串

题目描述 假设 str1 长度为 N N N&#xff0c;str2 长度为 M M M&#xff0c;求 str1 和 str2 的最长公共子串。 思路分析 示例&#xff1a;str1 “12abcd456”, str2 “7abcd89”&#xff0c;则str1和str2的最长公共子串为 abcd。 注意&#xff0c;子串是连续的。 动…

C. Anna, Svyatoslav and Maps(floyd + 思维)

Problem - C - Codeforces 给你一个有n个顶点的无权图&#xff0c;以及由m个顶点的序列p1,p2,...,pm给出的路径&#xff08;该路径不一定简单&#xff09;&#xff1b;对于每个1≤i<m&#xff0c;有一个弧从pi到pi1。 如果v是p的子序列&#xff0c;v1p1&#xff0c;vkpm&a…

JavaScript有几种数据类型,分别是什么?

在JavaScript中&#xff0c;我们可以分成两种类型&#xff1a;基本类型 复杂类型&#xff08;引用类型&#xff09; 两种类型的区别是&#xff1a;存储位置不同 基本类型主要为以下六种&#xff1a; Number、String、Boolean、Undefined、Null、Symbol 复杂类型/引用类型统称为…

C++ const关键字

参考资料&#xff1a; 【C const的各种用法详解】【const用法深入浅出】 - COS - 博客园 (cnblogs.com) const的基本概念&#xff1a; const名叫常量限定符&#xff0c;用来限定特定变量&#xff0c;以通知编译器该变量是不可修改的。习惯性的使用const&#xff0c;可以避免在函…

PostgreSQL环境搭建和主备构建

目录 1 Windows 上安装 PostgreSQL2 docker安装PostgreSQL2.1 检索当前镜像2.2. 拉取当前镜像2.3 创建挂载文件夹2.4 启动镜像2.5 查看日志2.7 查看进程2.8 使用连接 3 postgresql主从主备搭建3.1 安装好网络源&#xff08;主1.11、从1.12&#xff09;3.2 安装postgresql&#…

Python OpenCV 3.x 示例:1~5

原文&#xff1a;OpenCV 3.x with Python By Example 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 本文来自【ApacheCN 计算机视觉 译文集】&#xff0c;采用译后编辑&#xff08;MTPE&#xff09;流程来尽可能提升效率。 当别人说你没有底线的时候&#xff0c;你最…

一定要会的算法复杂度分析

本文首发自「慕课网」&#xff0c;想了解更多IT干货内容&#xff0c;程序员圈内热闻&#xff0c;欢迎关注"慕课网"&#xff01; 原作者&#xff1a;s09g|慕课网讲师 我们知道面对同一道问题时可能有多种解决方案。自然地&#xff0c;我们会将多种方法进行比较。那么…