news 2026/5/20 7:48:15

行为型设计模式——中介者模式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
行为型设计模式——中介者模式

文章目录

    • 中介者模式
      • 结构
      • 实现
      • 特点

中介者模式

为了有一个好的面向对象的设计,我们必须创建许多相互交互的类。如果不应用某些原则,最终的框架将以一团糟而告终,其中每个对象都依赖于许多其他对象才能运行。为了避免紧密耦合的框架,我们需要一种机制来促进对象之间的交互,其方式是对象不知道其他对象的存在。

对于那些对象之间存在复杂交互关系的系统,中介者模式(Mediator Pattern)提供了一种简单化复杂交互的解决方案。

中介模式定义了一个对象,该对象封装了一组对象如何交互。使用中介模式,对象之间的通信被封装在中介对象中。对象不再直接相互通信,而是通过中介器进行通信。这减少了通信对象之间的依赖性,从而减少了耦合。

用一个中介对象(中介者)来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

通过引入中介者来简化对象之间的复杂交互,中介者模式是“迪米特法则”的一个典型应用。

场景

表单验证问题

假如在修改用户资料页,有许多表单组件(如:文本框、复选框、列表框、按钮等),某些表单可能会存在联动(如:地址级联菜单、提交后会验证所有表单并显示错误信息),以表单验证为例,如果要完成验证提示功能,你按钮类需要关联页面所有表单元素,随着控件增多维护非常困难,控件之间的耦合度非常高,如果有重复逻辑,也无法复用。

使用中介者模式,来停止组件直接的直接交流。将页面本身作为中介者,页面知道自己所有的子组件,不需要新增依赖关系。之前, 当用户点击按钮后, 它必须对所有表单元素数值进行校验。 而现在它的唯一工作是将点击事件通知给对页面。 收到通知后, 页面可以自行校验数值或将任务委派给各元素。这样一来, 按钮不再与多个表单元素相关联, 而仅依赖于页面类。

采用这种方式, 中介者模式让你能在单个中介者对象中封装多个对象间的复杂关系网。 类所拥有的依赖关系越少, 就越易于修改、 扩展或复用。

类比现实世界

交通拥挤的时候,通过交警来疏通。如果驾驶员直接相互协商车辆之间的行进顺序,那就是后果可能会打起来吧!

结构

在中介者模式结构图中包含如下几个角色:

  • Mediator (中介者): 接口声明了与组件交流的方法, 但通常仅包括一个通知方法。 组件可将任意上下文 (包括自己的对象) 作为该方法的参数, 只有这样接收组件和发送者类之间才不会耦合。
  • Component (组件):是各种包含业务逻辑的类。 每个组件都有一个指向中介者的引用, 该引用被声明为中介者接口类型。 组件不知道中介者实际所属的类, 因此你可通过将其连接到不同的中介者以使其能在其他程序中复用。
  • Concrete Mediator (具体中介者):封装了多种组件间的关系。 具体中介者通常会保存所有组件的引用并对其进行管理, 甚至有时会对其生命周期进行管理。

组件并不知道其他组件的情况。 如果组件内发生了重要事件, 它只能通知中介者。 中介者收到通知后能轻易地确定发送者, 这或许已足以判断接下来需要触发的组件了。

对于组件来说, 中介者看上去完全就是一个黑箱。 发送者不知道最终会由谁来处理自己的请求, 接收者也不知道最初是谁发出了请求。

实现

// 抽象的中介机构classMediatorOrg{public:voidaddMember(Country*country);virtualvoiddeclare(string msg,Country*country,string name=string())=0;virtual~MediatorOrg(){}protected:map<string,Country*>m_countryMap;};#include<iostream>#include"Mediator.h"#include"Country.h"usingnamespacestd;// 基类的成员添加函数voidMediatorOrg::addMember(Country*country){m_countryMap.insert(make_pair(country->getName(),country));}// 在子类中重写发表声明的函数voidWorldGovt::declare(string msg,Country*country,string name){if(m_countryMap.find(name)!=m_countryMap.end()){string str=msg+"【来自: "+country->getName()+"】";m_countryMap[name]->setMessage(str);}}
// 世界政府classCountry;classWorldGovt:publicMediatorOrg{public:voiddeclare(string msg,Country*country,string name=string())override;};#include<iostream>#include"Mediator.h"#include"Country.h"usingnamespacestd;// 基类的成员添加函数voidMediatorOrg::addMember(Country*country){m_countryMap.insert(make_pair(country->getName(),country));}// 在子类中重写发表声明的函数voidWorldGovt::declare(string msg,Country*country,string name){if(m_countryMap.find(name)!=m_countryMap.end()){string str=msg+"【来自: "+country->getName()+"】";m_countryMap[name]->setMessage(str);}}
// 革命军classGeMingArmy:publicMediatorOrg{public:voiddeclare(string msg,Country*country,string name=string())override;};// 在子类中重写发表声明的函数voidGeMingArmy::declare(string msg,Country*country,string name){string str=msg+"【来自: "+country->getName()+"】";for(constauto&item:m_countryMap){if(item.second==country){continue;}item.second->setMessage(str);}}
// 抽象国家类classCountry{public:Country(MediatorOrg*mediator):m_mediator(mediator){}// 发表声明virtualvoiddeclare(string msg,string country)=0;virtualvoidsetMessage(string msg)=0;virtualstringgetName()=0;virtual~Country(){}protected:MediatorOrg*m_mediator=nullptr;};#pragmaonce#include<string>#include<iostream>#include"Mediator.h"usingnamespacestd;// 抽象国家类classCountry{public:Country(MediatorOrg*mediator):m_mediator(mediator){}// 发表声明virtualvoiddeclare(string msg,string country)=0;virtualvoidsetMessage(string msg)=0;virtualstringgetName()=0;virtual~Country(){}protected:MediatorOrg*m_mediator=nullptr;};// 阿拉巴斯坦classAlabasta:publicCountry{public:usingCountry::Country;voiddeclare(string msg,string country)override{m_mediator->declare(msg,this,country);}voidsetMessage(string msg)override{cout<<"阿拉巴斯坦得到的消息: "<<msg<<endl;}stringgetName()override{return"阿拉巴斯坦";}};// 德雷斯罗萨classDressrosa:publicCountry{public:usingCountry::Country;voiddeclare(string msg,string country)override{m_mediator->declare(msg,this,country);}voidsetMessage(string msg)override{cout<<"德雷斯罗萨得到的消息: "<<msg<<endl;}stringgetName()override{return"德雷斯罗萨";}};// 露露西亚王国classLulusia:publicCountry{public:usingCountry::Country;voiddeclare(string msg,string country)override{m_mediator->declare(msg,this,country);}voidsetMessage(string msg)override{cout<<"露露西亚得到的消息: "<<msg<<endl;}stringgetName()override{return"露露西亚";}};// 卡玛巴卡王国classKamabaka:publicCountry{public:usingCountry::Country;voiddeclare(string msg,string country)override{m_mediator->declare(msg,this,country);}voidsetMessage(string msg)override{cout<<"卡玛巴卡得到的消息: "<<msg<<endl;}stringgetName()override{return"卡玛巴卡";}};
intmain(){// 世界政府WorldGovt*world=newWorldGovt;Alabasta*alaba=newAlabasta(world);Dressrosa*dresa=newDressrosa(world);// 世界政府添加成员world->addMember(alaba);world->addMember(dresa);// 世界政府成员发声alaba->declare("德雷斯罗萨倒卖军火, 搞得我国连年打仗, 必须给个说法!!!",dresa->getName());dresa->declare("天龙人都和我多弗朗明哥做生意, 你算老几, 呸!!!",alaba->getName());cout<<"======================================"<<endl;// 革命军GeMingArmy*geming=newGeMingArmy;Lulusia*lulu=newLulusia(geming);Kamabaka*kama=newKamabaka(geming);geming->addMember(lulu);geming->addMember(kama);lulu->declare("我草, 我的国家被伊姆毁灭了!!!",lulu->getName());deleteworld;deletealaba;deletedresa;deletegeming;deletelulu;deletekama;return0;}

特点

中介者模式在事件驱动类软件中应用较为广泛,特别是基于GUI(Graphical User Interface,图形用户 界面)的应用软件,此外,在类与类之间存在错综复杂的关联关系的系统中,中介者模式都能得到较好的 应用。

当一些对象和其他对象紧密耦合以致难以对其进行修改时;当组件因过于依赖其他组件而无法在不同应用中复用时;当为了能在不同情景下复用一些基本行为,导致需要被迫创建大量组件子类时,都可使用中介者模式。

主要优点

  • 中介者模式简化了对象之间的交互,它用中介者和同事的一对多交互代替了原来同事之间的多对多交互,一对多关系更容易理解、维护和扩展,将原本难以理解的网状结构转换成相对简单的星型结构。
  • 中介者模式可将各同事对象解耦。中介者有利于各同事之间的松耦合,我们可以独立的改变和复用每一个同事和中介者,增加新的中介者和新的同事类都比较方便,更好地符合“开闭原则”。
  • 可以减少子类生成,中介者将原本分布于多个对象间的行为集中在一起,改变这些行为只需生成新的中介者子类即可,这使各个同事类可被重用,无须对同事类进行扩展。

主要缺点

  • 一段时间后, 中介者可能会演化成为上帝对象。

适用环境

  • 当一些对象和其他对象紧密耦合以致难以对其进行修改时, 可使用中介者模式。该模式让你将对象间的所有关系抽取成为一个单独的类, 以使对于特定组件的修改工作独立于其他 组件。
  • 当组件因过于依赖其他组件而无法在不同应用中复用时, 可使用中介者模式。应用中介者模式后,每个组件不再知晓其他组件的情况。 尽管这些组件无法直接交流, 但它们仍 可通过中介者对象进行间接交流。 如果你希望在不同应用中复用一个组件, 则需要为其提供一个新 的中介者类。
  • 如果为了能在不同情景下复用一些基本行为, 导致你需要被迫创建大量组件子类时, 可使用中介者 模式。由于所有组件间关系都被包含在中介者中, 因此你无需修改组件就能方便地新建中介者类以定义新 的组件合作方式。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/20 7:48:15

异常处理与性能调优:熬夜、加班与医美术后的“内服架构”实战指南

在互联网与高科技行业&#xff0c;系统的稳定运行往往伴随着开发者的极度透支。作为常年面对高并发需求和深夜发版的“IT 民工”或高压职场人&#xff0c;我们经常会遇到这样的尴尬场景&#xff1a;连续两周的 996 之后&#xff0c;面对电脑屏幕黑屏时的倒影&#xff0c;发现自…

作者头像 李华
网站建设 2026/5/20 7:48:01

国产SD-WAN/SASE技术架构深度解析:从核心能力到行业落地

摘要随着企业上云和多分支跨地域组网成为常态&#xff0c;传统专线与VPN架构在时延、稳定性及运维成本方面的局限性日益凸显。SD-WAN与SASE作为一种全新的网络架构&#xff0c;正成为企业网络升级的主流选择。本文将从纯技术角度&#xff0c;深度解析国产SD-WAN/SASE解决方案的…

作者头像 李华
网站建设 2026/5/20 7:47:36

智能纸板开料计算器——让纸箱计价与算料更高效

紫垣商驿 智能纸板开料计算器——让纸箱计价与算料更高效&#x1f539; 核心功能&#xff1a;精准计算&#xff0c;一“键”搞定多盒型支持&#xff1a;外箱&#xff08;平口/对口&#xff09;、飞机盒、内盒、天地盒&#xff08;上盖/下底&#xff09;、中封箱、侧封箱、全翼…

作者头像 李华
网站建设 2026/5/20 7:46:27

【AI入门知识点】RAG 是什么?为什么它能让 AI 不再胡说八道?

为什么 ChatGPT 有时一本正经地胡说八道&#xff1f; 为什么企业知识库问答越来越火&#xff1f; 为什么很多公司做 AI 项目时&#xff0c;都绕不开 RAG&#xff1f; 为什么大模型明明很强&#xff0c;却还是需要“外挂”&#xff1f;这些问题背后。其实都指向一个核心概念&…

作者头像 李华
网站建设 2026/5/20 7:41:38

FakeLocation虚拟定位:Android应用级位置伪装完全指南

FakeLocation虚拟定位&#xff1a;Android应用级位置伪装完全指南 【免费下载链接】FakeLocation Xposed module to mock locations per app. 项目地址: https://gitcode.com/gh_mirrors/fak/FakeLocation 在数字时代&#xff0c;位置隐私和地理灵活性变得前所未有的重要…

作者头像 李华
网站建设 2026/5/20 7:41:04

《流畅的Python》读书笔记03(补充01): 丰富的序列 - Python序列类型核心解析

《流畅的 Python》第 2 章“丰富的序列”系统性地阐述了 Python 序列类型的体系结构、核心操作及其背后的设计哲学。本章内容可归纳为以下四个核心模块&#xff1a; 一、序列类型的分类体系 Python 序列从两个正交维度进行分类&#xff0c;形成了清晰的类型矩阵。 分类维度类…

作者头像 李华