Java设计模式-中介者模式

中介者模式(Mediator Pattern)是行为型设计模式之一,它的核心思想是引入一个中介者对象来封装一系列对象之间的交互。

简单来说,就是让原本杂乱无章的"网状结构"通信,变成井井有条的"星型结构"通信。这就好比现实中的房产中介:房主不需要直接认识租客,租客也不需要直接认识房主,他们只需要通过中介来传递信息即可。

🎯 核心角色

中介者模式主要包含以下四个核心角色:

抽象中介者(Mediator):定义了同事对象用来通信的接口(如 sendMessage)。

具体中介者(ConcreteMediator):实现了中介者接口。它知道所有的具体同事对象,并负责协调各个同事对象之间的交互逻辑。

抽象同事类(Colleague):定义了同事类的接口,并持有一个对中介者对象的引用。

具体同事类(ConcreteColleague):实现了抽象同事类。它不再直接与其他同事通信,而是通过中介者来完成交互。

📐 结构演变:从网状到星型

没有使用中介者时(网状结构):假设有 N 个组件,如果它们需要两两通信,依赖关系会呈指数级增长(复杂度 O(N2)O(N2) )。改一处代码可能牵动全身。

使用中介者后(星型结构):所有组件只和"中介者"通信。组件之间不再有直接依赖,新增或修改组件不会影响其他组件,复杂度降至 O(N)O(N) 。

💻 代码实现示例(聊天室场景)

我们模拟一个简单的聊天室,用户之间不直接发消息,而是通过聊天室(中介者)来转发。

  1. 定义抽象中介者和具体中介者
java 复制代码
import java.util.*;

// 抽象中介者
interface ChatMediator {
    void addUser(User user);
    void sendMessage(String message, User sender);
}

// 具体中介者:聊天室
class ChatRoom implements ChatMediator {
    private List<User> users = new ArrayList<>();

    @Override
    public void addUser(User user) {
        users.add(user);
    }

    @Override
    public void sendMessage(String message, User sender) {
        // 遍历所有用户,将消息转发给除了发送者之外的人
        for (User user : users) {
            if (user != sender) {
                user.receive(message);
            }
        }
    }
}
  1. 定义同事类
java 复制代码
// 抽象同事类
abstract class User {
    protected ChatMediator mediator;
    protected String name;

    public User(ChatMediator mediator, String name) {
        this.mediator = mediator;
        this.name = name;
    }

    public abstract void send(String message);
    public abstract void receive(String message);
}

// 具体同事类
class ChatUser extends User {
    public ChatUser(ChatMediator mediator, String name) {
        super(mediator, name);
        mediator.addUser(this); // 注册到中介者
    }

    @Override
    public void send(String message) {
        System.out.println(name + " 发送: " + message);
        mediator.sendMessage(message, this); // 通过中介者发送
    }

    @Override
    public void receive(String message) {
        System.out.println(name + " 收到: " + message);
    }
}
  1. 客户端测试
java 复制代码
public class MediatorDemo {
    public static void main(String[] args) {
        ChatMediator chatRoom = new ChatRoom();
        
        User alice = new ChatUser(chatRoom, "Alice");
        User bob = new ChatUser(chatRoom, "Bob");
        User charlie = new ChatUser(chatRoom, "Charlie");

        // Alice 发送消息,Bob 和 Charlie 会收到
        alice.send("大家好!");
    }
}

输出结果:

Alice 发送: 大家好!

Bob 收到: 大家好!

Charlie 收到: 大家好!

✅ 优缺点分析

优点:

降低耦合度:同事对象之间不再相互引用,只依赖中介者,符合"迪米特法则"(最少知道原则)。

易于维护和扩展:交互逻辑集中在中介者中。如果要修改交互规则,只需修改中介者,而无需改动各个同事类。

复用性高:同事对象可以独立变化,更容易被复用。

缺点:

中介者可能过于复杂:如果系统中同事类太多,或者交互逻辑极其复杂,中介者会变成一个包含大量逻辑的"上帝类",难以维护。

可能成为性能瓶颈:所有消息都经过中介者转发,如果中介者处理能力不足,会影响整体性能。

🚀 适用场景

中介者模式(Mediator Pattern)的核心价值在于解耦。当系统中对象之间的交互关系变得复杂、呈现出"网状结构"时,就是中介者模式大显身手的时候。简单来说,它的使用场景通常符合这样一个特征:多个对象之间需要相互通信,且这种通信关系经常变化或难以维护。

结合我搜索到的信息,以下是中介者模式最典型的具体应用场景:

1. 图形用户界面(GUI)组件交互

这是教科书级的应用场景。

场景描述:在一个复杂的表单或对话框中,多个组件(如按钮、文本框、下拉列表、复选框)的状态是相互关联的。

在一个登录窗口中,只有当"用户名"和"密码"输入框都不为空时,"登录"按钮才变为可用状态。

勾选"全选"复选框时,下面所有的子选项都要被选中。

为什么用中介者:如果不使用中介者,按钮就需要持有对文本框的引用,文本框也需要监听按钮的状态,导致类之间互相依赖,代码极其混乱。通过引入"窗口对象"作为中介者,所有组件只需向窗口报告事件,由窗口统一判断并更新其他组件的状态。

2. 聊天系统与即时通讯

场景描述:在群聊或多人在线游戏中,用户(或玩家)之间需要发送消息。

具体例子:微信群聊:你发消息给群,群再把消息分发给其他人,你不需要直接连接到每个群成员的设备。游戏中的队伍频道。

为什么用中介者:如果用户之间直接通信(网状连接),新增一个用户需要建立 N 次连接;通过"聊天服务器"或"频道"作为中介者,用户只需连接服务器,由服务器负责转发(星型结构),极大地降低了网络复杂度。

3. 智能家居与物联网(IoT)设备联动

场景描述:家里的灯光、空调、窗帘、音响等设备需要根据场景自动协作。

具体例子:"观影模式":按下遥控器,灯光自动关闭,窗帘拉上,电视和音响开启。"回家模式":门锁打开后,灯自动亮起,空调调到舒适温度。

为什么用中介者:如果让灯直接去控制窗帘,再让窗帘去通知空调,设备之间会高度耦合,无法独立更换设备。通过"智能中枢"(如 HomeAssistant 或手机 App)作为中介者,设备只向中枢发送状态(如"门开了"),由中枢决定调度哪些设备,实现"即插即用"。

4. 微服务与分布式系统协调

场景描述:在复杂的业务流程中,涉及多个微服务(如订单、库存、支付、物流)。

具体例子:电商下单流程:创建订单 -> 扣减库存 -> 发起支付 -> 通知物流。使用消息队列(如 Kafka、RabbitMQ)或服务注册中心(如 Nacos、Eureka)。

为什么用中介者:如果服务之间直接调用(A调B,B调C),一旦某个服务宕机或下线,整个链条都会断裂。通过消息中间件或注册中心作为"中介者",服务之间通过发布/订阅消息进行异步通信,实现了服务解耦和流量削峰。

5. 工作流与审批系统

场景描述:OA 系统、财务报销系统,涉及多角色按规则流转任务。

具体例子:请假流程:员工提交 -> 主管审批 -> HR 备档 -> 财务发薪。采购流程:申请 -> 部门经理 -> 财务审核 -> 总经理审批。

为什么用中介者:如果把审批逻辑硬编码在代码里,每增加一个审批节点就要改代码。通过"流程引擎"作为中介者,将流程定义为配置文件(如 XML 或 JSON),引擎根据配置动态决定下一步该谁审批,实现了逻辑与代码分离。

6. 航空交通管制

场景描述:多架飞机在机场附近飞行。

具体例子:飞机之间不直接协商谁先降落,而是听从塔台的指挥。

为什么用中介者:这是现实世界中最直观的中介者例子。塔台(Mediator)掌握了所有飞机(Colleague)的位置和状态,统一调度以避免碰撞。

7.何时应该使用中介者模式?

你可以通过以下三个"信号"来判断是否需要使用中介者模式:

  • 网状依赖:类图中线条交错杂乱,对象之间互相持有引用。
  • 修改困难:想修改一个对象的行为,结果发现必须去修改它所依赖的其他好几个对象的代码。
  • 复用困难:因为对象依赖太多其他对象,导致你无法单独把这个对象拿出来用在别的地方。

注意:虽然中介者模式很好用,但要避免将其变成"上帝类"(God Class),即中介者承担了过多的职责,导致中介者本身代码过于臃肿难以维护。

相关推荐
忧郁的Mr.Li16 小时前
设计模式--工厂模式
设计模式
HL_风神18 小时前
C++设计模式浅尝辄止
c++·设计模式
会员果汁19 小时前
22.设计模式-享元模式(Flyweight)
设计模式·哈希算法·享元模式
亓才孓21 小时前
[设计模式]单例模式的懒汉式写法
单例模式·设计模式
小码过河.1 天前
设计模式——访问者模式
设计模式·访问者模式
Engineer邓祥浩1 天前
设计模式学习(21) 23-19 备忘录模式
学习·设计模式·备忘录模式
亓才孓1 天前
[设计模式]单例模式饿汉式写法
单例模式·设计模式
代码丰1 天前
设计模式:不再手动 set DTO,采用 Builder 模式
设计模式
老蒋每日coding1 天前
AI Agent 设计模式系列(二十一)—— 探索和发现设计模式
人工智能·设计模式