中介者模式的理解和实践

news2024/12/26 11:21:47

一、中介者模式概述

        中介者模式(Mediator Pattern),也称为调解者模式或调停者模式,是一种行为设计模式。它的核心思想是通过引入一个中介者对象来封装一系列对象之间的交互,使得这些对象不必直接相互作用,从而达到松散耦合的效果。这种设计模式主要用于降低系统中对象之间的耦合度,提高系统的灵活性和可维护性。

        中介者模式定义了一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,并且可以独立地改变它们之间的交互。在这个模式中,各个对象不再直接相互引用和通信,而是通过中介者来进行间接通信。这样,不仅降低了对象之间的依赖关系,还简化了对象之间的交互逻辑。

 

二、中介者模式的结构

        中介者模式通常包含以下几个关键角色:

  1. 抽象中介者(Mediator):定义一个接口,该接口用于定义各同事(Colleague)对象之间进行通信需要的方法。
  2. 具体中介者(ConcreteMediator):实现抽象中介者接口,通过协调各个同事对象来实现协作行为,了解并维护它的各个同事,它维持了对各个同事对象的引用。
  3. 抽象同事类(Colleague):定义各个同事类公有的方法,并声明了一些抽象方法来供子类实现,同时它维持了一个对抽象中介者类的引用,其子类可以通过该引用来与中介者通信。
  4. 具体同事类(ConcreteColleague):实现抽象同事类,每一个同事对象在需要和其他同事对象通信时,先与中介者通信,通过中介者来间接完成与其他同事类的通信。

三、中介者模式的理解

  1. 降低耦合度:通过引入中介者对象,各个对象之间的直接依赖关系被减少,使得系统结构更加灵活和可扩展。
  2. 简化交互:中介者模式将对象之间的多对多交互关系转换为中介者与各个对象之间的一对多关系,简化了对象之间的交互逻辑。
  3. 易于维护和扩展:由于对象之间的交互被集中到中介者对象中,因此当需要修改或扩展对象之间的交互时,只需修改中介者对象,而不需要修改各个对象的代码。

        然而,中介者模式也有其局限性。如果系统中存在大量的同事类,中介者可能会变得非常复杂,难以维护。因此,在实际应用中需要权衡利弊,根据具体情况决定是否采用该模式。

四、中介者模式的实践

        下面我们通过具体的Java代码示例来展示中介者模式的实践应用。

示例一:简单的聊天系统

        假设我们要设计一个可以让多人参与进去的聊天室,该聊天室需要实现发送消息和新增用户的功能。

        首先,我们定义聊天室的接口ChatRoom,其中包含两个方法sendMessageaddUser,分别代表发送消息和新增用户。这里的ChatRoom就是抽象的中介者类。

public interface ChatRoom {
    void sendMessage(String msg, String userId);
    void addUser(User user);
}


        然后,我们创建一个ChatRoom的实现类ChatRoomImpl,使用addUser来添加需要聊天的用户对象,同时这里再使用一个Map来保存添加时需要用来进行通信的对象列表。在发送消息sendMessage的方法中,我们通过userId指定某个对象来接收消息。

import java.util.HashMap;
import java.util.Map;

public class ChatRoomImpl implements ChatRoom {
    private Map<String, User> usersMap = new HashMap<>();

    @Override
    public void sendMessage(String msg, String userId) {
        User u = usersMap.get(userId);
        u.receive(msg);
    }

    @Override
    public void addUser(User user) {
        this.usersMap.put(user.getId(), user);
    }
}


        接下来,我们定义一个抽象组件类User,它持有一个ChatRoom的引用,并声明了发送消息send和接收消息receive的抽象方法。

public abstract class User {
    private ChatRoom mediator;
    private String id;
    private String name;

    public User(ChatRoom room, String id, String name) {
        this.mediator = room;
        this.name = name;
        this.id = id;
    }

    public abstract void send(String msg, String userId);

    public abstract void receive(String msg);

    public ChatRoom getMediator() {
        return mediator;
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}


        然后,我们实现一个具体的组件类ChatUser,并实现发送消息send和接收消息receive的方法。

public class ChatUser extends User {

    public ChatUser(ChatRoom room, String id, String name) {
        super(room, id, name);
    }

    @Override
    public void send(String msg, String userId) {
        getMediator().sendMessage(msg, userId);
    }

    @Override
    public void receive(String msg) {
        System.out.println(getName() + "收到消息: " + msg);
    }
}


        最后,我们在客户端代码中创建中介者和同事对象的实例,并将它们关联起来。

public class ChatDemo {
    public static void main(String[] args) {
        ChatRoom chatRoom = new ChatRoomImpl();
        User user1 = new ChatUser(chatRoom, "1", "张三");
        User user2 = new ChatUser(chatRoom, "2", "李四");

        chatRoom.addUser(user1);
        chatRoom.addUser(user2);

        user1.send("你好, 李四", "2");
        user2.send("你好, 张三", "1");
    }
}


        运行上述代码,输出结果如下:

李四收到消息: 你好, 李四
张三收到消息: 你好, 张三


        通过这个示例,我们可以看到,聊天系统中的用户对象(User)通过中介者(ChatRoom)来进行间接通信,而不需要直接引用对方。这样,不仅降低了用户对象之间的耦合度,还简化了用户之间的交互逻辑。

示例二:多架飞机降落

        假设有多架飞机需要跑道降落,塔台作为中介者指挥飞机降落。每一架飞机都是一个组件,拥有一些相同的行为,塔台作为中介者负责指挥飞机的降落。

        首先,我们定义抽象中介者接口TowerMediator,它包含通知方法notify、注册方法register和移除方法remove

public interface TowerMediator {
    void notify(String type, String track);
    void register(AirplaneComponent colleague);
    void remove(AirplaneComponent colleague);
}


        然后,我们实现具体的中介者类AirlinerConcreteMediator,它持有一个List来管理组件对象(即飞机)。

import java.util.ArrayList;
import java.util.List;

public class AirlinerConcreteMediator implements TowerMediator {
    private List<AirplaneComponent> colleagues = new ArrayList<>();

    @Override
    public void notify(String type, String track) {
        for (AirplaneComponent airplaneComponent : colleagues) {
            if (!type.equalsIgnoreCase(airplaneComponent.getAirplaneType())) {
                continue;
            }
            airplaneComponent.landing(track);
        }
    }

    @Override
    public void register(AirplaneComponent colleague) {
        colleagues.add(colleague);
    }

    @Override
    public void remove(AirplaneComponent colleague) {
        colleagues.remove(colleague);
    }
}


        接下来,我们定义抽象组件类AirplaneComponent,它持有一个中介者对象的引用,并声明了一个抽象方法landing

public abstract class AirplaneComponent {
    public String airplaneType;
    private TowerMediator towerMediator;

    public AirplaneComponent(String airplaneType, TowerMediator towerMediator) {
        this.airplaneType = airplaneType;
        this.towerMediator = towerMediator;
    }

    public abstract void landing(String track);

    public TowerMediator getTowerMediator() {
        return towerMediator;
    }
}


        然后,我们实现具体的组件类AirlinerConcreteComponent,它代表客机。

public class AirlinerConcreteComponent extends AirplaneComponent {

    public AirlinerConcreteComponent(String airplaneType, TowerMediator towerMediator) {
        super(airplaneType, towerMediator);
    }

    @Override
    public void landing(String track) {
        System.out.println(airplaneType + "正在跑道" + track + "上降落");
    }
}


        最后,我们在客户端代码中创建中介者和组件对象的实例,并将它们关联起来。

// 客户端代码
public class AirportDemo {
    public static void main(String[] args) {
        // 创建中介者(塔台)
        TowerMediator towerMediator = new AirlinerConcreteMediator();
 
        // 创建具体的组件(飞机),并注册到中介者
        AirplaneComponent airplane1 = new AirlinerConcreteComponent("波音737", towerMediator);
        AirplaneComponent airplane2 = new AirlinerConcreteComponent("空客A320", towerMediator);
        AirplaneComponent airplane3 = new AirlinerConcreteComponent("波音787", towerMediator);
 
        // 通知中介者进行降落安排(这里假设有两个跑道:Runway 1 和 Runway 2)
        towerMediator.notify("波音737", "Runway 1");
        towerMediator.notify("空客A320", "Runway 2");
        towerMediator.notify("波音787", "Runway 1"); // 假设波音787可以等待或使用另一个空闲跑道
 
        // 注意:由于中介者内部已经维护了组件的列表,因此不需要显式地移除组件,
        // 除非在程序的某个阶段需要动态地卸载组件。
    }
}

        在这个示例中,AirportDemo类的main方法是客户端代码,它创建了中介者AirlinerConcreteMediator的实例,并创建了多个具体的组件(飞机)实例,这些实例都被注册到了中介者中。然后,通过调用中介者的notify方法,模拟了飞机请求降落的过程,并分配了跑道。

        运行AirportDemo类的main方法,您将看到类似以下的输出:

波音737 正在跑道 Runway 1 上降落
空客A320 正在跑道 Runway 2 上降落
波音787 正在跑道 Runway 1 上降落

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

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

相关文章

【蓝桥杯每日一题】砍竹子

砍竹子 2024-12-7 蓝桥杯每日一题 砍竹子 STL 贪心 题目大意 这天, 小明在砍竹子, 他面前有 nn 棵竹子排成一排, 一开始第 ii 棵竹子的 高度为 h i h_i hi​. 他觉得一棵一棵砍太慢了, 决定使用魔法来砍竹子。魔法可以对连续的一 段相同高度的竹子使用, 假设这一段竹子的高度为…

泷羽sec-burpsuite(5)app渗透测试(上) 学习笔记

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&a…

从一个Bug谈前端响应拦截器的应用

一、问题场景 今天在开发商品管理系统时&#xff0c;遇到了一个有趣的问题&#xff1a;当添加重复的商品编号时&#xff0c;页面同时弹出了两条 "商品编号已存在" 错误提示&#xff1a; 这个问题暴露了前端错误处理机制的混乱&#xff0c;让我们从这个问题出发&…

量子变分算法---损失函数

引子 关于损失函数&#xff0c;我们知道在强化学习中&#xff0c;会有一个函数&#xff0c;用来表示模型每一次行为的分数&#xff0c;通过最大化得分&#xff0c;建立一个正反馈机制&#xff0c;若模型为最优则加分最多&#xff0c;若决策不佳则加很少分或者扣分。而在神经网络…

车间的图纸在传输过程的安全怎么保障?

车间的图纸在传输过程的安全保障&#xff0c;要从很多方面出发分析&#xff0c;本文从以下几点为大家列出几个&#xff0c;看看有没有你想知道的呢~ 1、采用先进的图纸加密软件 采用先进的加密算法对图纸进行加密处理&#xff0c;确保图纸文件在存储、传输和使用过程中的安全性…

MQTT消息服务器mosquitto介绍及说明

Mosquitto是一个开源的消息代理软件&#xff0c;支持MQTT协议&#xff08;消息队列遥测传输协议&#xff09;。MQTT是一种轻量级的发布/订阅消息传输协议&#xff0c;专为低带宽、不可靠网络环境下的物联网设备通信而设计。以下是关于Mosquitto服务器的一些介绍和说明&#xff…

想在iPad上远程操作安卓手机的APP,怎样实现iPad远程控制安卓?

学生党或互联网行业的打工人&#xff0c;人手连三台电子设备也很常见&#xff0c;手机、平板还有笔记本电脑一大堆&#xff0c;如果出门要全带上&#xff0c;背包压力也变大。 有没有想过用远程控制功能&#xff0c;让iPad远程控制安卓手机&#xff1f;这样做&#xff0c;出门就…

VBA高级应用30例应用在Excel中的ListObject对象:向表中添加注释

《VBA高级应用30例》&#xff08;版权10178985&#xff09;&#xff0c;是我推出的第十套教程&#xff0c;教程是专门针对高级学员在学习VBA过程中提高路途上的案例展开&#xff0c;这套教程案例与理论结合&#xff0c;紧贴“实战”&#xff0c;并做“战术总结”&#xff0c;以…

Spring源码分析之Bean的实例化(createBeanInstance())

前言: 通过Spring源码分析之Bean的创建过程(createBean)-CSDN博客我们可以知道如果没有动态代理以及循环依赖的前提之下的话那么一个普通的单例Bean的创建后就是实例化,属性填充,初始化这三个步骤那么这篇文章的话我们就先说一下实例化也就是doCreateBean方法里面的createBeanI…

一次“okhttp访问间隔60秒,提示unexpected end of stream“的问题排查过程

一、现象 okhttp调用某个服务&#xff0c;如果第二次访问间隔上一次访问时间超过60s&#xff0c;返回错误&#xff1a;"unexpected end of stream"。 二、最终定位原因&#xff1a; 空闲连接如果超过60秒&#xff0c;服务端会主动关闭连接。此时客户端恰巧访问了这…

蓝桥杯准备训练(lesson5 ,c++)

单目操作符与第 2 章 C/C输⼊输出&#xff08;上&#xff09; 8. 单⽬操作符8.1 和--8.1.1 前置 和 后置8.1.2 前置-- 和 后置-- 8.2 和 - 第 2 章 C/C输⼊输出&#xff08;上&#xff09;1. getchar 和 putchar1.1 getchar()1.2 putchar() 2. scanf 和 printf2.1 printf2.1.1…

Linux系统挂载exfat格式U盘教程,触觉智能RK3562开发板演示

本文介绍Linux系统&#xff08;Ubuntu/Debian通用&#xff09;挂载exfat格式U盘的方法&#xff0c;触觉智能RK3562开发板演示&#xff0c;搭载4核A53处理器&#xff0c;主频高达2.0GHz&#xff1b;内置独立1Tops算力NPU&#xff0c;可应用于物联网网关、平板电脑、智能家居、教…

LeetCode 0935.骑士拨号器:动态规划(DP)

【LetMeFly】935.骑士拨号器&#xff1a;动态规划(DP) 力扣题目链接&#xff1a;https://leetcode.cn/problems/knight-dialer/ 象棋骑士有一个独特的移动方式&#xff0c;它可以垂直移动两个方格&#xff0c;水平移动一个方格&#xff0c;或者水平移动两个方格&#xff0c;垂…

No.4 笔记 探索网络安全:揭开Web世界的隐秘防线

在这个数字时代&#xff0c;网络安全无处不在。了解Web安全的基本知识&#xff0c;不仅能保护我们自己&#xff0c;也能帮助我们在技术上更进一步。让我们一起深入探索Web安全的世界&#xff0c;掌握那些必备的安全知识&#xff01; 1. 客户端与WEB应用安全 前端漏洞&#xff1…

PHP使用local-proxy的一种思路! | 架构师之路(19)

《架构师之路&#xff1a;架构设计中的100个知识点》 19.脚本语言使用长连接的一种思路 脚本类语言&#xff0c;例如PHP&#xff0c;不能像C/Java那样能搞服务常驻内存&#xff0c;不能搞长连接&#xff1f; 为什么脚本语言要搞长连接&#xff1f; 脚本类语言每次访问后端数据库…

【51单片机】程序实验1112.外部中断-定时器中断

主要参考学习资料&#xff1a;B站【普中官方】51单片机手把手教学视频 前置知识&#xff1a;C语言 单片机套装&#xff1a;普中STC51单片机开发板A4标准版套餐7 码字不易&#xff0c;求点赞收藏加关注(•ω•̥) 有问题欢迎评论区讨论~ 目录 程序实验11&12.外部中断-定时器…

驱动---1.DAC8552实现三角波输出

最近开始进行新项目的研发&#xff0c;考虑用DAC做一个前级输出&#xff0c;选择了DAC8552这个器件的一个模块&#xff0c;用了野火的指南者做主控&#xff0c;芯片是STM32F103VET6&#xff0c;主频是72MHz。 一、器件手册重要信息提取 1.DAC8552具有十六位的分辨率、双通道输…

虚幻引擎生存建造系统

先做一个建造预览模式&#xff0c;按下按键B后进入建造预览模式 首先创建自定义事件Preview Loop 用射线追踪摆放物体预览位置&#xff0c;并做一个预览材质 增强输入设置按键 每帧判断是否进入建造模式 预览模式制作成功&#xff01; 接着做点击左键放置物品&#xff0…

IP研究 | 大数据洞察黄油小熊的爆火之路

一只来自泰国的小熊在国内红成了顶流。 今年&#xff0c;黄油小熊以烘焙店“打工人”的超萌形象迅速走红&#xff0c;2个月内火遍中国的社交媒体&#xff0c;泰国门店挤满飘洋过海求合影的中国粉丝&#xff0c;根据数说故事全网大数据洞察&#xff0c;黄油小熊2024年度的线上声…

深度学习案例:DenseNet + SE-Net

本文为为&#x1f517;365天深度学习训练营内部文章 原作者&#xff1a;K同学啊 一 回顾DenseNet算法 DenseNet&#xff08;Densely Connected Convolutional Networks&#xff09;是一种深度卷积神经网络架构&#xff0c;提出的核心思想是通过在每一层与前面所有层进行直接连接…