设计模式(十四)中介者模式

news2024/9/28 19:20:35

请直接看原文:

原文链接:设计模式(十四)中介者模式_设计模式之中介模式-CSDN博客

-------------------------------------------------------------------------------------------------------------------------------- 

前言

写了很多篇设计模式的文章,才发现没有讲关于设计模式的分类,那么这一篇就补上这一内容,顺便带来中介者模式的讲解。并与此前讲过的代理模式和外观模式做对比。

1.设计模式的分类

GoF提出的设计模式总共有23种,根据目的准则分类分为三大类:

  • 创建型模式,共五种:单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。
  • 结构型模式,共七种:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
  • 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

另外随着设计模式的发展也涌现出很多新的设计模式:它们分别是规格模式、对象池模式、雇工模式、黑板模式和空对象模式等。

2.中介者模式

从前面讲到的设计模式的分类中,我们应该得知中介者模式是行为型模式的一种,旨在处理类或对象如何交互及如何分配职责。
中介者模式又叫做调停者模式,名字跟出国留学中介和房产中介是类似的。拿房产中介来说,现在房子买家和房子卖家非常多,如果任由房子买家和房子卖家自由交易,则会导致不同的买家和卖家之间有很多交互,一个买家会和多个卖家进行交涉,同样的一个卖家也会和多个买家进行交涉。如果在买房的过程中出现纠纷问题,则很难进行解决。就如下图所示一样。

可以看出房子买家和卖家进行了很多错综复杂的交互,并且买家A和卖家B,买家D和卖家D还产生了纠纷,一看到这个图我们就觉得的晕,当然比我们晕的还有房子买家和卖家。我们在 设计模式(一)设计六大原则这篇文章讲过迪米特原则,这个原则所说的就是要尽量减少对象之间的交互,如果两个对象之间不必彼此直接通信,那么这两个对象就不应当发生任何直接的相互作用,如果其中的一个对象需要调用另一个对象的某一个方法的话,可以通过第三者转发这个调用。迪米特原则同样适用于本场景,我们可以引入第三者也就是房产中介。它的出现不需要买家和卖家进行直接交涉,而是通过房产中介而进行交涉。并且也不容易出现买卖家之间纠纷,因为有中介者房产中介进行第三方监督。如下图所示。

图中的关系清晰了很多。回到我们软件开发中,我们为了减少对象之间的交互和耦合,符合迪米特原则,那么就可以使用中介者模式,先来学习下中介者模式的定义。

中介者模式定义

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

中介者模式结构图如下图所示。


在中介者模式中有如下角色:
- Mediator:抽象中介者角色,定义了同事对象到中介者对象的接口。
- ConcreteMediator:具体中介者角色,它从具体的同事对象接收消息,向具体同事发出命令。
- Colleague:抽象同事角色,定义了中介者对象接口,它只知道中介者而不知道其他同事对象。
- ConcreteColleague:具体同事角色,每个具体同事类都知道自己在小范围内的行为,而不知道它在大范围内的目的。

中介者模式简单实现

中介者模式可以拿武侠来举例,江湖中门派众多,门派之前因为想法不同会有很多的利益冲突,这样就会带来无休止的纷争。为了江湖的安宁,大家推举出了一个大家都认可的武林盟主来对江湖纷争进行调停。
前段时间武当派和峨眉派的的弟子被大力金刚指所杀,大力金刚指是少林派的绝学,因为事情重大,而且少林派实力强大,武当派和峨眉派不能够直接去少林派去问罪,只能上报武林盟主由武林盟主出面进行调停,如下图所示。

这里写图片描述

抽象中介者角色

首先我们创建抽象中介者类,在这个例子中,它是一个武林联盟类,如下所示。

public abstract class WulinAlliance {
    public abstract void notice(String message, United united);
}

notice方法用于向门派发送通知,其中United为抽象同事类也就是门派类,接下来我们来创建它。

抽象同事角色
public abstract class United {
    protected WulinAlliance wulinAlliance;
    public United(WulinAlliance wulinAlliance){
        this.wulinAlliance=wulinAlliance;
    }
}

门派类(抽象同事类)会在构造方法中得到武林联盟类(抽象中介者类)。

具体同事角色

具体同事类包括武当派、峨眉派和少林派,如下所示。

/**
 * 具体同事类(武当)
 */

public class Wudang extends United {
    public Wudang(WulinAlliance wulinAlliance) {
        super(wulinAlliance);
    }
    public void sendAlliance(String message) {
        wulinAlliance.notice(message, this);
    }
    public void getNotice(String message) {
        System.out.println("武当收到消息:" + message);
    }
}

/**
 * 具体同事类(峨眉派)
 */
public class Emei extends United {
    public Emei(WulinAlliance wulinAlliance) {
        super(wulinAlliance);
    }
    public void sendAlliance(String message) {
        wulinAlliance.notice(message, Emei.this);
    }
    public void getNotice(String message) {
        System.out.println("峨眉收到消息:" + message);
    }
}

/**
 * 具体同事类(少林派)
 */
public class Shaolin extends United {
    public Shaolin(WulinAlliance wulinAlliance) {
        super(wulinAlliance);
    }
    public void sendAlliance(String message){
        wulinAlliance.notice(message,Shaolin.this);
    }
    public void getNotice(String message){
        System.out.println("少林收到消息:"+message);
    }
}

武当、峨眉和少林类都有两个方法,其中getNotice方法是自有方法,对于其他的门派(同事类)和武林联盟(中介者)没有依赖,只是用来接收武林盟主的通知。sendAlliance方法则是依赖方法,它必须通过武林盟主才能完成行为。

具体中介者角色

具体中介者类则是武林盟主类,如下所示

public class Champions extends WulinAlliance {
    private Wudang wudang;
    private Shaolin shaolin;
    private Emei emei;
    public void setWudang(Wudang wudang) {
        this.wudang = wudang;
    }
    public void setEmei(Emei emei) {
        this.emei = emei;
    }
    public void setShaolin(Shaolin shaolin) {
        this.shaolin = shaolin;
    }
    @Override
    public void notice(String message, United united) {
        if (united == wudang) {
            shaolin.getNotice(message);
        } else if (united == emei) {
            shaolin.getNotice(message);
        } else if (united == shaolin) {
            wudang.getNotice(message);
            emei.getNotice(message);
        }
    }
}

武林盟主需要了解所有的门派,所以需要用setter来持有武当、峨眉和少林的引用。notice方法会根据不同门派发来的消息,转而通知给其他的门派。比如武当发来的消息,武林盟主就会将消息通知给少林。

客户端调用
public class Client {
    public static void main(String[]args) {
        Champions champions=new Champions();
        Wudang wudang=new Wudang(champions);
        Shaolin shaolin=new Shaolin(champions);
        Emei emei=new Emei(champions);
        champions.setWudang(wudang);
        champions.setShaolin(shaolin);
        champions.setEmei(emei);
        wudang.sendAlliance("武当弟子被少林大力金刚指所杀");
        emei.sendAlliance("峨眉弟子被少林大力金刚指所杀");
        shaolin.sendAlliance("少林弟子绝不会做出这种事情");
    }
}

首先创建武林盟主类Champions 并传入到各个门派类,接着调用武林盟主类的setter方法传入各个门派类,最后调用各个门派的sendAlliance方法通过武林盟主类向其他门派发送消息。

输出结果为:
少林收到消息:武当弟子被少林大力金刚指所杀
少林收到消息:峨眉弟子被少林大力金刚指所杀
武当收到消息:少林弟子绝不会做出这种事情
峨眉收到消息:少林弟子绝不会做出这种事情

接下来给出这个例子的UML图,如下所示。
这里写图片描述

中介者模式的优缺点和使用场景

优点
符合迪米特原则,将原有的一对多的依赖变成了一对一的依赖,降低类间的耦合。

缺点
中介者会变得庞大且复杂,原本多个对象直接的相互依赖变成了中介者和多个同事类的依赖关系,同事类越多,中介者的逻辑就越复杂。

使用场景
中介者模式很容易实现呢,但是也容易误用,不要着急使用,先要思考你的设计是否合理。
当对象之间的交互变多时,为了防止一个类会涉及修改其他类的行为,可以使用中介者模式,将系统从网状结构变为以中介者为中心的星型结构。

3.代理模式、外观模式和中介者模式对比

当我们学完中介者模式是不是会觉得和此前讲过的代理模式和外观模式有些类似呢?现在我们一一来将它们进行对比。

代理模式和中介者模式

代理模式是结构型设计模式,它有很多种类型,主要是在访问对象时引入一定程度的间接性,由于有间接性,就可以附加多种的用途,比如进行权限控制。中介者模式则是为了减少对象之间的相互耦合。虽然网上有很多代理模式和中介者模式的对比,但是在我看来这两者实际上并没有可比性,只是看起来有些类似罢了。

外观模式和中介者模式

外观模式主要是以封装和隔离为主要任务,中介者则是调停同事类之间的关系,因此,中介者具有部分业务的逻辑控制。他们之间的主要区别为:
- 外观模式的子系统如果脱离外观模式还是可以运行的,而中介者模式增加了业务逻辑,同事类不能脱离中介者而独自存在。
- 外观模式中,子系统是不知道外观类的存在的,而中介者模式中,每个同事类都知道中介者。
- 外观模式将子系统的逻辑隐藏,用户不知道子系统的存在,而中介者模式中,用户知道同事类的存在。

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

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

相关文章

洛谷 B3620 x 进制转 10 进制

题目描述 给一个小整数 x 和一个 x 进制的数 S。将 S 转为 10 进制数。对于超过十进制的数码,用 A,B,…… 表示。 输入格式 第一行一个整数 x; 第二行一个字符串 S。 输出格式 输出仅包含一个整数,表示答案。 输入输出样例…

《TCP/IP详解 卷一》第12章 TCP初步介绍

目录 12.1 引言 12.1.1 ARQ和重传 12.1.2 滑动窗口 12.1.3 变量窗口:流量控制和拥塞控制 12.1.4 设置重传的超时值 12.2 TCP的引入 12.2.1 TCP服务模型 12.2.2 TCP可靠性 12.3 TCP头部和封装 12.4 总结 12.1 引言 关于TCP详细内容,原书有5个章…

CSS 自测题 -- 用 flex 布局绘制骰子(一、二、三【含斜三点】、四、五、六点)

一点 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>css flex布局-画骰子</title><sty…

Day13:信息打点-JS架构框架识别泄漏提取API接口枚举FUZZ爬虫插件项目

目录 JS前端架构-识别&分析 JS前端架构-开发框架分析 前端架构-半自动Burp分析 前端架构-自动化项目分析 思维导图 章节知识点 Web&#xff1a;语言/CMS/中间件/数据库/系统/WAF等 系统&#xff1a;操作系统/端口服务/网络环境/防火墙等 应用&#xff1a;APP对象/API接…

OJ_重复者

题干 C实现 #include <stdio.h> #include <string.h> using namespace std; void square(int curSize, int patSize, char pattern[3000][3000], char picture[3000][3000], char last[3000][3000]) {if (curSize 1) {for (int i 0; i < patSize; i) {for (i…

《高性能MYSQL》-架构,锁,事务

MYSQL的逻辑架构 第一层&#xff0c;客户端层&#xff1a;包含了连接处理&#xff0c;身份验证&#xff0c;确保安全性等 第二层&#xff0c;包含了mysql大部分的核心功能&#xff0c;查询解析&#xff0c;分析&#xff0c;优化&#xff0c;以及所有的内置函数&#xff08;例如…

Redis--线程模型详解

Redis线程模型 Redis内部使用的文件事件处理器&#xff08;基于Reactor模式开发的&#xff09;file event handler是单线程的&#xff0c;所以Redis线程模型才叫单线程模型&#xff0c;它采用IO多路复用机制同时监听多个socket&#xff0c;当被监听的socket准备好执行accep、r…

深度相机xyz点云文件三维坐标和jpg图像文件二维坐标的相互变换函数

深度相机同时拍摄xyz点云文件和jpg图像文件。xyz文件里面包含三维坐标[x,y,z]和jpg图像文件包含二维坐标[x&#xff0c;y],但是不能直接进行变换&#xff0c;需要一定的步骤来推演。 下面函数是通过box二维框[xmin, ymin, xmax, ymax, _, _ ]去截取xyz文件中对应box里面的点云…

洛谷P5717 三角形分类

给出三条线段a,b,c 的长度&#xff0c;均是不大于 1000010000 的正整数。打算把这三条线段拼成一个三角形&#xff0c;它可以是什么三角形呢&#xff1f; 如果三条线段不能组成一个三角形&#xff0c;输出Not triangle&#xff1b;如果是直角三角形&#xff0c;输出Right tria…

图的简单介绍

定义及术语 G(V,E)&#xff1a;图G的顶点集为V&#xff0c;边集为E。分为有向图和无向图两类。 顶点的度&#xff1a;与该结点相连的边的条数。 出度&#xff1a;顶点的出边条数 入度&#xff1a;顶点的入边条数 顶点的权值称为点权&#xff0c;边的权值称为边权。 存储 1.邻…

Day14:信息打点-主机架构蜜罐识别WAF识别端口扫描协议识别服务安全

目录 Web服务器&应用服务器差异性 WAF防火墙&安全防护&识别技术 蜜罐平台&安全防护&识别技术 思维导图 章节知识点 Web&#xff1a;语言/CMS/中间件/数据库/系统/WAF等 系统&#xff1a;操作系统/端口服务/网络环境/防火墙等 应用&#xff1a;APP对象/…

c++基础知识补充6

new相比malloc可以操作自定义类型 开空间的同时调用构造函数初始化 new,delete和malloc,free要分组使用&#xff0c;否则结果不确定 new和delete本质是malloc和free的封装

香港服务器选择指南(挑选香港服务器的几个标准)

​  随着全球化的加速和互联网的普及&#xff0c;跨境访问和外贸活动越来越频繁。在这个背景下&#xff0c;香港服务器作为一种国际化的基础设施&#xff0c;受到了广泛欢迎。本文将探讨企业在选择香港服务器时应关注的几个标准事项。 1.可靠性和正常运行时间 停机可能会给企…

代码随想录算法训练营第46天| Leetcode 139.单词拆分、卡码网 56. 携带矿石资源(附带多重背包的基本解法和优化)

文章目录 Leetcode 139.单词拆分卡码网 56. 携带矿石资源方法一&#xff1a; 分组转化成01背包方法二&#xff1a; 转化成01背包完全背包&#xff08;基于方法一的小优化&#xff09;方法三&#xff1a; 二进制优化&#xff08;优化了方法一的分组方式&#xff09; Leetcode 13…

基于springboot的宠物咖啡馆平台的设计与实现论文

基于Spring Boot的宠物咖啡馆平台的设计与实现 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了基于Spring Boot的宠物咖啡馆平台的设计与实现的开发全过程。通过分析基于Spring Boot的宠物咖啡馆平台的设计与…

【Scratch画图100例】图49-scratch绘制直角风车 少儿编程 scratch编程画图案例教程 考级比赛画图集训案例

目录 scratch绘制直角风车 一、题目要求 1、准备工作 2、功能实现 二、案例分析 1、角色分析 2、背景分析 3、前期准备 三、实现流程 1、案例分析 2、详细过程 四、程序编写 五、考点分析 六、推荐资料 1、入门基础 2、蓝桥杯比赛 3、考级资料 4、视频课程 …

leetcode第 387 场周赛总结

很久没打周赛了&#xff0c;这周开始恢复 这次周赛&#xff0c;题目比较简单&#xff0c;第三道题有点浪费了时间&#xff0c;思路是对的&#xff0c;但是被我把问题复杂化了。 晚上来写题解和总结

YOLOv9有效提点|加入SGE、Ge、Global Context、GAM等几十种注意力机制(四)

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; 一、本文介绍 本文只有代码及注意力模块简介&#xff0c;YOLOv9中的添加教程&#xff1a;可以看这篇文章。 YOLOv9有效提点|加入SE、CBAM、ECA、SimA…

C++入门全集(3):类与对象【中】

一、前言 经过上一篇文章的学习&#xff0c;我们知道类中由成员变量和成员函数组成 本章的内容&#xff0c;就围绕类的6个默认成员函数展开讲解 如果一个类中什么都没有&#xff0c;简称为空类 class Date {};然而&#xff0c;空类真的像表面一样什么都没有吗&#xff1f;不…

HBM(High Bandwidth Memory)

选择正确的高带宽内存 构建高性能芯片的选择越来越多&#xff0c;但附加内存的选择却几乎没有变化。为了在汽车、消费和超大规模计算中实现最大性能&#xff0c;选择取决于一种或多种 DRAM&#xff0c;而最大的权衡是成本与速度。 尽管多年来人们一直在努力用更快、更便宜或更…