设计模式学习(20) 23-18 中介者模式

文章目录

  • 0.个人感悟
  • [1. 概念](#1. 概念)
  • [2. 适配场景](#2. 适配场景)
    • [2.1 适合的场景](#2.1 适合的场景)
    • [2.2 常见场景举例](#2.2 常见场景举例)
  • [3. 实现方法](#3. 实现方法)
    • [3.1 实现思路](#3.1 实现思路)
    • [3.2 UML类图](#3.2 UML类图)
    • [3.3 代码示例](#3.3 代码示例)
  • [4. 优缺点](#4. 优缺点)
    • [4.1 优点](#4.1 优点)
    • [4.2 缺点](#4.2 缺点)

0.个人感悟

  • 中介者模式核心是解耦,抽取一个中间层中介对象,让原来相关耦合的对象(多对对)都只与中介对象交互(一对多),由中介对象维护关系和交互
  • 优缺点很明显,最明显优点是解耦,对象关系变得清晰;最明显缺点是对象的交互都由中介完成,容易导致代码杂乱膨胀。看了很多示例,中介者的逻辑都很复杂,比如智能家居,会设置多个模式,然后很多if else
  • 建议实际使用时,对于中介者这块结合业务做好设计和实现

1. 概念

英文定义(《设计模式:可复用面向对象软件的基础》)

Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.

中文翻译

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

理解

  • 中介者模式的核心思想是集中控制多个对象之间的交互逻辑
  • 将原本对象间的直接通信转为通过中介者间接通信
  • 对象之间不再相互持有引用,只依赖中介者
  • 交互逻辑从中介者的"同事类"中抽离,集中到中介者中管理
  • 本质上是一种"多个对象通信的解耦"模式

2. 适配场景

2.1 适合的场景

  1. 复杂网状交互:当多个对象间存在复杂的网状引用关系,交互逻辑混乱时
  2. 通信协议统一化:需要定义一组对象间的通信协议,且这组协议可能变化时
  3. 行为可复用性差:由于对象间强耦合导致行为难以复用

2.2 常见场景举例

  1. 航空管制系统:飞机、塔台、跑道之间的通信通过空中交通管制中心协调
  2. 聊天室应用:多个用户通过聊天服务器中转消息,而不是直接P2P通信
  3. MVC架构:Controller作为Model和View之间的中介者
  4. GUI对话框:对话框中的各种控件(按钮、输入框、复选框)通过对话框协调

3. 实现方法

3.1 实现思路

  1. 识别交互群体:找出需要解耦的相互通信对象集合
  2. 定义中介者接口:声明协调各对象交互的方法
  3. 创建具体中介者:实现中介者接口,持有所有"同事"对象的引用
  4. 定义同事接口:声明同事对象的基本行为,包含中介者引用
  5. 重构同事类
    • 移除与其他同事的直接引用
    • 添加中介者引用
    • 将原本直接调用改为通过中介者转发
  6. 客户端配置:创建中介者并注册所有同事对象

3.2 UML类图

角色说明:

  • Mediator(中介者接口):定义同事对象通信的接口
  • ConcreteMediator(具体中介者):实现中介者接口,协调各同事对象的交互,知道所有同事
  • Colleague(同事接口):定义同事类的接口,持有中介者引用
  • ConcreteColleague(具体同事):实现同事接口,每个同事只知道中介者,不知道其他同事

3.3 代码示例

背景:以租房中介为例,简化一下流程

  • 租客和房东互不依赖,都只与中介打交道
  • 租客行为简化为 浏览房源、请求看房、接受消息
  • 房东行为简化为发布房源、接受消息
    设计

中介接口

  • 定义租客和房东诉求
java 复制代码
public interface RentalMediator {  
    /**  
     * @param renter 租客  
     * @description 租客注册  
     * @author bigHao  
     * @date 2026/1/26  
     **/    
     void registerRenter(Renter renter);  
  
    /**  
     * @param landlord 房东  
     * @description 房东注册  
     * @author bigHao  
     * @date 2026/1/26  
     **/    
     void registerLandlord(Landlord landlord);  
  
    /**  
     * @param renter  租客  
     * @param request 请求信息  
     * @description 查看房源列表  
     * @author bigHao  
     * @date 2026/1/26  
     **/    
     void listHouses(Renter renter, String request);  
  
    /**  
     * @param landlord 房东  
     * @param house    房子信息  
     * @description 添加房源  
     * @author bigHao  
     * @date 2026/1/26  
     **/    
     void addHouse(Landlord landlord, House house);  
  
    /**  
     * @param renter  租客  
     * @param houseId 房子id  
     * @description 预约看房  
     * @author bigHao  
     * @date 2026/1/26  
     **/    
     void arrangeViewing(Renter renter, String houseId);  
}

同事接口和实现

  • 这里抽象出父类person,公共属性为id和中介者,接受通知方法简化成只打印信息,不区分细节
  • 租客类定义租客行为,都调用中介方法
  • 房东类定义房东行为,都调用中介方法
java 复制代码
public abstract class Person {  
    RentalMediator rentalMediator;  
  
    protected String id;  
  
    public String getId() {  
        return id;  
    }  
  
    public Person(RentalMediator rentalMediator, String id) {  
        this.rentalMediator = rentalMediator;  
        this.id = id;  
    }  
  
    /**  
     * @param info 通知信息  
     * @description 通知  
     * @author bigHao  
     * @date 2026/1/26  
     **/    
     public void notify(String info) {  
        System.out.println(STR."\{id} 收到消息: \{info}");  
    }  
}

public class Renter extends Person {  
  
    public Renter(RentalMediator rentalMediator, String id) {  
        super(rentalMediator, id);  
        rentalMediator.registerRenter(this);  
    }  
  
    /**  
     * @param request 请求  
     * @description 搜索房源  
     * @author bigHao  
     * @date 2026/1/26  
     **/    public void searchHouse(String request) {  
        rentalMediator.listHouses(this, request);  
    }  
  
    /**  
     * @param houseId 房子id  
     * @description 请求看房  
     * @author bigHao  
     * @date 2026/1/26  
     **/    public void requestViewing(String houseId) {  
        rentalMediator.arrangeViewing(this, houseId);  
    }  
}

public class Landlord extends Person {  
  
    public Landlord(RentalMediator rentalMediator, String id) {  
        super(rentalMediator, id);  
        rentalMediator.registerLandlord(this);  
    }  
  
    /**  
     * @param house 房子  
     * @description 发布房源  
     * @author bigHao  
     * @date 2026/1/26  
     **/    public void pushHouse(House house) {  
        rentalMediator.addHouse(this, house);  
    }  
}

// 参数类
public class House {  
    // 房东id  
    private String landlordId;  
  
    // 房子id  
    private String houseId;  
  
    // 信息  
    private String info;  
  
    public House(String landlordId, String houseId, String info) {  
        this.landlordId = landlordId;  
        this.houseId = houseId;  
        this.info = info;  
    }  
  
    public String getLandlordId() {  
        return landlordId;  
    }  
  
    public void setLandlordId(String landlordId) {  
        this.landlordId = landlordId;  
    }  
  
    public String getHouseId() {  
        return houseId;  
    }  
  
    public void setHouseId(String houseId) {  
        this.houseId = houseId;  
    }  
  
    public String getInfo() {  
        return info;  
    }  
  
    public void setInfo(String info) {  
        this.info = info;  
    }  
}

具体中介者

  • 持有房东和租客列表
  • 简化房东-房子映射,house map 的key为房子id,vlue为房子信息,里面包含房东id
  • 简化匹配房源逻辑,简单用contains来判断
java 复制代码
public class ConcreteMediator implements RentalMediator {  
    private List<Renter> renters = new ArrayList<>();  
    private List<Landlord> landlords = new ArrayList<>();  
  
    private Map<String, House> houses = new HashMap<>();  
  
    @Override  
    public void registerRenter(Renter renter) {  
        System.out.println(STR."\{renter.getId()} 注册成为租客");  
        renters.add(renter);  
    }  
  
    @Override  
    public void registerLandlord(Landlord landlord) {  
        System.out.println(STR."\{landlord.getId()} 注册成为房东");  
        landlords.add(landlord);  
    }  
  
    @Override  
    public void listHouses(Renter renter, String request) {  
        System.out.println(STR."\{renter.getId()} 找房");  
  
        // 匹配  
        List<String> housesIds = searchHousesByInfo(request);  
  
        // 发送返回结果给租客  
        String join = String.join(",", housesIds);  
        renter.notify("请求结果列表: " + join);  
    }  
  
    @Override  
    public void addHouse(Landlord landlord, House house) {  
        System.out.println(STR."\{house.getLandlordId()} 发布房子 \{house.getInfo()}");  
        houses.put(house.getHouseId(), house);  
    }  
  
    @Override  
    public void arrangeViewing(Renter renter, String houseId) {  
        System.out.println(STR."\{renter.getId()} 请求看房 \{houseId}");  
  
        String landlordId = houses.get(houseId).getLandlordId();  
        // 查找房东  
        Landlord landlord = landlords.stream().filter(item -> item.getId().equals(landlordId)).findFirst().get();  
  
        String msg = STR."明天15:00 一起看房";  
  
        // 给租客发消息  
        renter.notify(msg);  
        // 给房东发消息  
        landlord.notify(msg);  
    }  
  
    private List<String> searchHousesByInfo(String request) {  
        return houses.values().stream()  
                .filter(house -> house.getInfo() != null && house.getInfo().contains(request))  
                .map(House::getHouseId)  
                .collect(Collectors.toList());  
    }  
}

测试

java 复制代码
public class Client {  
    static void main() {  
        // 注册  
        RentalMediator rentalMediator = new ConcreteMediator();  
  
        System.out.println("===注册===");  
        Renter renter = new Renter(rentalMediator, "租客张三");  
  
        Landlord landlord = new Landlord(rentalMediator, "房东李四");  
  
        // 房源发布  
        System.out.println("===发布房源===");  
        House house1 = new House("房东李四", "房子001", "房租1000 拎包入住");  
        House house2 = new House("房东李四", "房子002", "房租2000 临近地铁18号线");  
        House house3 = new House("房东李四", "房子003", "房租2000 学区附近");  
        House house4 = new House("房东李四", "房子004", "房租5000 面朝大海");  
  
        landlord.pushHouse(house1);  
        landlord.pushHouse(house2);  
        landlord.pushHouse(house3);  
        landlord.pushHouse(house4);  
  
        // 查房  
        System.out.println("===查看房源===");  
        renter.searchHouse("2000");  
  
        // 看房  
        System.out.println("===看房===");  
        renter.requestViewing("房子002");  
    }  
}

输出

复制代码
===注册===
租客张三 注册成为租客
房东李四 注册成为房东
===发布房源===
房东李四 发布房子 房租1000 拎包入住
房东李四 发布房子 房租2000 临近地铁18号线
房东李四 发布房子 房租2000 学区附近
房东李四 发布房子 房租5000 面朝大海
===查看房源===
租客张三 找房
租客张三 收到消息: 请求结果列表: 房子003,房子002
===看房===
租客张三 请求看房 房子002
租客张三 收到消息: 明天15:00 一起看房
房东李四 收到消息: 明天15:00 一起看房

4. 优缺点

4.1 优点

  1. 高内聚低耦合(核心原则):

    • 符合迪米特法则:对象只与中介者通信,减少对象间的直接依赖
    • 降低耦合度:将网状依赖变为星型结构,对象间耦合度显著降低
  2. 可维护性

    • 集中控制:交互逻辑集中在中介者中,易于理解和维护
    • 简化协议:将多对多交互简化为一对多交互
  3. 可扩展性

    • 新增同事类时,只需修改中介者,不影响其他同事
    • 可以复用同事类,因为它们不直接依赖其他具体类
  4. 稳定性

    • 单个同事类的修改不会波及其他同事
    • 交互逻辑变化只需修改中介者

4.2 缺点

  1. 中介者可能成为"上帝对象"

    • 中介者可能承担过多职责,变得庞大复杂
    • 可能违反单一职责原则
  2. 性能影响

    • 所有通信都经过中介者,可能成为性能瓶颈
    • 增加了一层间接调用,略微影响性能
  3. 设计复杂性

    • 需要精心设计中介者接口,否则可能限制灵活性
    • 过度使用可能导致系统结构不清晰

参考:

相关推荐
观音山保我别报错2 小时前
Spring Boot 项目学习内容详解(一)
spring boot·后端·学习
●VON2 小时前
Flutter for OpenHarmony:基于三层 Tab 架构与数据模型解耦的 TodoList 产品化演进
学习·flutter·架构·openharmony·布局·技术
机器学习之心2 小时前
集群中继无人机应急通信双层多目标协同优化部署:融合无监督学习与凸优化及启发式算法的MATLAB代码
学习·无人机·启发式算法·双层多目标协同优化
@––––––2 小时前
论文学习笔记:FAST - 高效的视觉-语言-动作模型动作分词技术
笔记·学习
Gain_chance2 小时前
22-学习笔记尚硅谷数仓搭建-日志表建表语句解析、数据装载及脚本装载数据
数据仓库·笔记·学习
不穿格子的程序员2 小时前
设计模式篇2——观察者模式:以直播间送礼系统举例
java·观察者模式·设计模式
小码过河.2 小时前
设计模式——解释器模式
java·设计模式·解释器模式
知识分享小能手3 小时前
Oracle 19c入门学习教程,从入门到精通,Oracle数据库控制 —— 事务与并发控制详解(14)
数据库·学习·oracle
其美杰布-富贵-李3 小时前
Spring Event 学习笔记
笔记·学习·spring·事件消息