设计模式学习(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 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意2 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码2 天前
嵌入式学习路线
学习
毛小茛2 天前
计算机系统概论——校验码
学习
babe小鑫2 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms2 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下2 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。2 天前
2026.2.25监控学习
学习
im_AMBER2 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J2 天前
从“Hello World“ 开始 C++
c语言·c++·学习