中介者模式:解耦对象间复杂交互的设计模式

中介者模式:解耦对象间复杂交互的设计模式

一、模式核心:用中介者统一管理对象交互,避免两两直接依赖

当系统中多个对象之间存在复杂的网状交互时(如 GUI 界面中按钮、文本框、下拉框的联动),对象间直接调用会导致关系混乱、难以维护。

中介者模式(Mediator Pattern) 通过引入一个中介者对象(Mediator),将对象间的直接交互转换为与中介者的单向交互。所有对象只需与中介者通信,由中介者协调处理交互逻辑,从而实现对象间的松耦合。核心解决:

  • 交互复杂性:避免对象间形成复杂的依赖网络,降低系统复杂度。
  • 可维护性:交互逻辑集中在中介者中,修改时只需调整中介者,无需修改多个对象。
  • 扩展性:新增对象时只需实现与中介者的交互,不影响现有对象间的逻辑。

核心思想与 UML 类图

中介者模式包含以下角色:

  1. 中介者接口(Mediator):定义对象间交互的接口,如接收消息、分发消息。
  2. 具体中介者(Concrete Mediator):实现中介者接口,协调具体同事对象的交互。
  3. 同事类(Colleague):依赖中介者,通过中介者间接交互,不直接调用其他同事。

二、核心实现:GUI 界面组件的交互协调

1. 定义中介者接口

java 复制代码
public interface Mediator {  
    void notify(Object sender, String event); // 接收消息(发送者、事件类型)  
}  

2. 实现具体中介者(处理组件联动)

java 复制代码
public class UIMediator implements Mediator {  
    private Button button;  
    private TextBox textBox;  
    private Dropdown dropdown;  

    // 设置中介者关联的组件  
    public void setButton(Button button) {  
        this.button = button;  
    }  

    public void setTextBox(TextBox textBox) {  
        this.textBox = textBox;  
    }  

    public void setDropdown(Dropdown dropdown) {  
        this.dropdown = dropdown;  
    }  

    @Override  
    public void notify(Object sender, String event) {  
        if (sender == button && "click".equals(event)) {  
            // 按钮点击时,获取文本框内容并更新下拉框  
            String text = textBox.getText();  
            dropdown.setSelectedItem(text);  
            System.out.println("按钮点击:设置下拉框选项为 " + text);  
        } else if (sender == dropdown && "select".equals(event)) {  
            // 下拉框选择时,清空文本框  
            textBox.clear();  
            System.out.println("下拉框选择:清空文本框");  
        }  
    }  
}  

3. 定义抽象同事类(组件基类)

java 复制代码
public abstract class UIComponent {  
    protected Mediator mediator;  

    public void setMediator(Mediator mediator) {  
        this.mediator = mediator;  
    }  

    protected void sendEvent(String event) {  
        if (mediator != null) {  
            mediator.notify(this, event); // 通过中介者发送事件  
        }  
    }  
}  

4. 实现具体同事类(按钮、文本框、下拉框)

按钮组件
java 复制代码
public class Button extends UIComponent {  
    public void onClick() {  
        System.out.println("按钮被点击");  
        sendEvent("click"); // 发送点击事件给中介者  
    }  
}  
文本框组件
java 复制代码
public class TextBox extends UIComponent {  
    private String text;  

    public String getText() {  
        return text;  
    }  

    public void setText(String text) {  
        this.text = text;  
    }  

    public void clear() {  
        text = "";  
        System.out.println("文本框已清空");  
    }  
}  
下拉框组件
java 复制代码
public class Dropdown extends UIComponent {  
    private String selectedItem;  

    public void setSelectedItem(String item) {  
        this.selectedItem = item;  
        System.out.println("下拉框选中:" + selectedItem);  
    }  
}  

5. 客户端初始化中介者与组件

java 复制代码
public class ClientDemo {  
    public static void main(String[] args) {  
        // 创建中介者和组件  
        UIMediator mediator = new UIMediator();  
        Button button = new Button();  
        TextBox textBox = new TextBox();  
        Dropdown dropdown = new Dropdown();  

        // 组件关联中介者  
        button.setMediator(mediator);  
        textBox.setMediator(mediator);  
        dropdown.setMediator(mediator);  

        // 中介者关联组件(双向绑定)  
        mediator.setButton(button);  
        mediator.setTextBox(textBox);  
        mediator.setDropdown(dropdown);  

        // 模拟用户操作:文本框输入内容,按钮点击触发联动  
        textBox.setText("Option A");  
        button.onClick(); // 按钮点击,通过中介者更新下拉框  

        System.out.println("\n模拟下拉框选择操作:");  
        mediator.notify(dropdown, "select"); // 下拉框选择,通过中介者清空文本框  
    }  
}  

输出结果

plaintext 复制代码
按钮被点击  
按钮点击:设置下拉框选项为 Option A  
下拉框选中:Option A  

模拟下拉框选择操作:  
下拉框选择:清空文本框  
文本框已清空  

三、框架与源码中的中介者实践

1. Spring MVC 的 Controller 作为中介者

在 Spring MVC 中,Controller 作为中介者协调 ModelView 的交互:

  • View(如 JSP)发送请求到 Controller
  • Controller 调用 Model 处理业务逻辑,再将结果返回给 View
java 复制代码
@Controller  
public class UserController {  
    @Autowired  
    private UserService userService; // Model 层  

    @GetMapping("/user/{id}")  
    public String getUser(@PathVariable int id, Model model) {  
        User user = userService.getUser(id);  
        model.addAttribute("user", user); // 中介者传递数据到 View  
        return "user.jsp"; // 中介者决定返回视图  
    }  
}  

2. Android 的 Activity 作为中介者

Android 中 Activity 作为中介者管理界面组件(ButtonEditText 等)的交互:

  • 组件通过 setOnClickListener 注册事件到 Activity
  • Activity 处理事件并协调组件状态更新。
java 复制代码
public class MainActivity extends AppCompatActivity {  
    private EditText editText;  
    private TextView textView;  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  

        editText = findViewById(R.id.edit_text);  
        textView = findViewById(R.id.text_view);  

        findViewById(R.id.button).setOnClickListener(v -> {  
            String text = editText.getText().toString();  
            textView.setText("输入内容:" + text); // 中介者协调组件交互  
        });  
    }  
}  

3. Java Swing 的 Event Dispatch Thread

Swing 通过事件分发线程(中介者)处理组件事件,避免组件间直接通信:

  • 按钮点击事件由 Event Dispatch Thread 接收并分发给注册的监听器。

四、避坑指南:正确使用中介者模式的 3 个要点

1. 避免中介者过度复杂

若中介者承担过多职责,会形成 "上帝对象"。可将中介者拆分为多个专用中介者(如订单中介者、支付中介者),或引入分层结构(如中介者 + 协调者)。

2. 平衡中介者与同事的职责

同事类应尽量保持简单,仅包含自身状态和基本操作,复杂逻辑集中在中介者中。若同事类需要频繁调用中介者,需检查是否违反单一职责原则。

3. 区分中介者模式与观察者模式

  • 中介者模式:对象间通过中介者间接交互,形成星型结构(非广播式)。
  • 观察者模式:主题与观察者是一对多的依赖关系,观察者被动接收通知(广播式)。

六、总结:何时该用中介者模式?

适用场景 核心特征 典型案例
对象间网状交互 多个对象间存在复杂直接调用 GUI 界面组件联动、分布式系统节点通信
系统重构解耦 遗留系统中对象间紧耦合,需简化依赖 微服务间消息路由、legacy 系统改造
集中式逻辑管理 需要将交互逻辑集中管理与维护 工作流引擎、交易系统规则引擎

中介者模式通过 "中心化管理" 的设计,有效降低了对象间的耦合度,提升了系统的可维护性和扩展性。下一篇我们将探讨访问者模式,解析如何分离数据结构与操作,敬请期待!

扩展思考:中介者模式的缺点

  • 中介者单点风险:中介者故障会导致整个系统交互失效,需通过冗余设计或分布式中介者缓解。
  • 调试难度增加:交互逻辑集中在中介者中,需借助日志或调试工具追踪消息流程。
相关推荐
aningxiaoxixi4 分钟前
JAVA之 Lambda
java·开发语言
月下点灯9 分钟前
使用Set集合新特性,快速实现一个商品SKU(单品)规格选择器
前端·javascript·vue.js
大侠Luffy9 分钟前
做了这些SEO动作,独立开发的网站开始被搜索引擎逐量收录
前端·seo
四棱子16 分钟前
炫酷!18.5kb实现流体动画,这个开源项目让个人主页瞬间高大上!
前端·开源
Sparkxuan17 分钟前
封装WebSocket
前端·websocket
工呈士17 分钟前
Redux 实践与中间件应用
前端·react.js·面试
Nano17 分钟前
深入解析 JavaScript 数据类型:从基础到高级应用
前端
无羡仙18 分钟前
浮动与BFC容器
前端
xphjj18 分钟前
树形数据模糊搜索
前端·javascript·算法
刺客_Andy18 分钟前
React 第三十四节 Router 开发中 useLocation Hook 的用法以及案例详解
前端·react.js