当前位置: 首页 > news >正文

23种设计模式-行为型模式-中介者

文章目录

  • 简介
  • 问题
  • 解决
    • 代码
    • 架构优势
  • 总结

简介

中介者是一种行为设计模式, 能让你减少对象之间混乱无序的依赖关系。该模式会限制对象之间的直接交互,强制让它们通过一个中介者对象进行合作。

问题

假如你有一个创建和修改用户资料的对话框,它由各种控件组成,例如文本框 ( T e x t F i e l d )、 复 选框 ( C h e c k b o x ) 和按钮 ( B u t t o n ) 等 。
用戶界面中各元素间的关系会随程序发展而变得混乱
某些表单元素之间可能会直接进行互动。比如,选中“我有一只猫”复选框后可能会显示一个隐藏文本框用于输入猫咪的名字。另一个例子是点击提交按钮后需要校验所有输入的内容。
元素间存在许多关联。 所以对某些元素进行修改可能会影响其他元素。
另外,如果直接在表单元素代码中实现业务逻辑,你就很难在程序其他表单中复用这些元素类。比如,由于复选框类与猫咪的文本框相耦合,所以就不能在其他表单中使用该复选框。所以要么使用渲染表单时用到的所有类, 要么一个都不用。

解决

中介者模式建议你停止组件之间的直接调用,让他们相互独立。这些组件必须调用中介者对象,通过中介者对象重定向调用行为,用间接的方式进行合作。最终,组件只依赖于一个中介者类,无需跟多个其他组件相耦合。
在编辑表单的例子中,对话框(Dialog) 类本身可以作为中介者 ,他很可能知道自己所有的子元素,因此不需要在这个类里引入新的依赖关系。
UI 元素必须通过中介者对象进行间接沟通
绝大部分重要的修改都在实际表单元素里进行。 我们还是回到提交按钮。之前,当用戶点击按钮后,它必须对所有表单内容进行校验。而 现在它的唯一工作是把点击事件通知给对话框。收到通知后,对话框可以自行校验数值或把任务委派给各个元素。这样一来,按钮不再与多个表单元素相关联, 而只依赖于对话框类。
你还可以为所有类型的对话框抽取通用接口,进一步削弱它的依赖性。接口里声明一个所有表单元素都能使用的通知方法,可用于把元素中发生的事件通知给对话框。这样一来,所有实现了这个接口的对话框都能使用这个提交按钮了。
采用这种方式,中介者模式让你能在单个中介者对象中封装多个对象之间的复杂关系网。我们知道,类所拥有的依赖关系越少,就越易于修改、扩展或 复用。

代码

// 1.Mediator接口
interface DialogMediator {
    void notify(Component sender, String event); // 统一事件通知口
}

// 2.Concrete Mediator(登录对话框)
class LoginDialogMediator implements DialogMediator {
    private CheckBox rememberMeBox;   // ComponentA
    private TextBox usernameTextBox;  // ComponentB
    private TextBox passwordTextBox;  // ComponentC
    private Button submitButton;      // ComponentD
    
    public LoginDialogMediator() {
        // 组件在中介内创建并建立双向引用
        rememberMeBox = new CheckBox(this);
        usernameTextBox = new TextBox(this);
        passwordTextBox = new TextBox(this);
        submitButton = new Button(this);
    }
    
    @Override
    public void notify(Component sender, String event) {
        if (sender == rememberMeBox && event.equals("check")) {
            toggleRememberMeConfig();
        } else if ((sender == usernameTextBox || sender == passwordTextBox) 
                   && event.equals("keypress")) {
            validateForm(); // 实时校验表单
        } else if (sender == submitButton && event.equals("click")) {
            handleSubmit();
        }
    }
    
    private void toggleRememberMeConfig() {
        System.out.println("记住密码配置更改:" + rememberMeBox.isChecked());
    }
    
    private void validateForm() {
        boolean isValid = !usernameTextBox.getText().isEmpty() && 
                          passwordTextBox.getText().length() >= 6;
        submitButton.setEnabled(isValid); // 联合控制按钮状态
    }
    
    private void handleSubmit() {
        System.out.println("提交用户:" + usernameTextBox.getText());
    }
}

// 3.Components实现
abstract class Component {
    protected DialogMediator dialog; // 持中介引用
    
    public Component(DialogMediator dialog) {
        this.dialog = dialog;
    }
    
    public abstract void triggerEvent(String event);
}

class CheckBox extends Component { // ComponentA
    private boolean checked;
    
    public CheckBox(DialogMediator dialog) { super(dialog); }
    
    public void toggle() {
        checked = !checked;
        dialog.notify(this, "check"); // 通知中介
    }
    public boolean isChecked() { return checked; }
    
    @Override
    public void triggerEvent(String event) { toggle(); }
}

class TextBox extends Component { // ComponentB/C
    private String text = "";
    
    public TextBox(DialogMediator dialog) { super(dialog); }
    
    public void input(String text) {
        this.text = text;
        dialog.notify(this, "keypress"); // 实时反馈输入
    }
    public String getText() { return text; }
    
    @Override
    public void triggerEvent(String event) { input(event); }
}

class Button extends Component { // ComponentD
    private boolean enabled = false;
    
    public Button(DialogMediator dialog) { super(dialog); }
    
    public void click() {
        if(enabled) dialog.notify(this, "click");
    }
    public void setEnabled(boolean state) {
        enabled = state;
        System.out.println("按钮状态:" + (state?"可用":"禁用"));
    }
    
    @Override
    public void triggerEvent(String event) { click(); }
}

// 4.Client使用
public class AuthDialogClient {
    public static void main(String[] args) {
        LoginDialogMediator dialog = new LoginDialogMediator();
        
        // 模拟用户交互流程
        dialog.getUsernameTextBox().triggerEvent("john");     // 输入用户名
        dialog.getPasswordTextBox().triggerEvent("123456");   // 输入密码
        dialog.getSubmitButton().triggerEvent("click");       // 成功提交
        
        dialog.getRememberMeBox().triggerEvent("check");      // 切换"记住我"
        dialog.getPasswordTextBox().triggerEvent("123");      // 触发按钮禁用
    }
}

架构优势

  1. 解耦组件:各组件仅依赖中介对象,无直接关联
  2. 集中控制:表单验证逻辑统一在validateForm()处理
  3. 扩展灵活:新增密码强度校验组件时不影响现有结构

总结

在这里插入图片描述

  1. 组件(Component)是各种包含业务逻辑的类。每个组件都有一 个指向中介者的引用,这个引用被声明成中介者接口类型。组件不知道中介者实际所属的类,因此你可以通过把它连接到不同的中介者来让它能在其他程序里复用。
  2. 中介者(Mediator)接口声明了与组件交流的方法,但通常只包 括一个通知方法。组件可把任意上下文(包括自己的对象)作为 这个方法的参数, 只有这样接收组件和发送者类之间才不会耦合。
  3. 具体中介者(Concrete Mediator) 封装了多种组件间的关系。 具体中介者通常会保存所有组件的引用并对其进行管理,甚至有时会对它的生命周期进行管理。
  4. 组件并不知道其他组件的情况。如果组件内发生了重要事件, 它只能通知中介者。中介者收到通知后能轻易地确定发送者,这就已经足够判断接下来需要触发的组件了。 对于组件来说,中介者看上去完全就是一个黑箱。发送者不知道最终会由谁来处理自己的请求,接收者也不知道最初是谁发出了请求。

相关文章:

  • 可以使用费曼学习法阅读重要的书籍
  • 【学Rust写CAD】34 精确 Alpha 混合函数(argb.rs补充方法)
  • 路由器的 WAN(广域网)口 和 LAN(局域网)口
  • 【微机及接口技术】- 第五章 输入输出与接口技术(下)
  • uniapp微信小程序引入vant组件库
  • docker部署rabbitmq
  • [刷题总结] 双指针 滑动窗口
  • 使用`sklearn`中的逻辑回归模型进行股票的情感分析,以及按日期统计积极和消极评论数量的功能
  • JavaScript箭头函数介绍(=>)(箭头函数不绑定自己的this,而是继承上下文的this;不能用于造函数)JavaScript =>
  • Linux网络应用层自定义协议与序列化
  • 导数的基本求导法则
  • 代码随想录算法训练营Day32| 完全背包问题(二维数组 滚动数组)、LeetCode 518 零钱兑换 II、377 组合总数 IV、爬楼梯(进阶)
  • 纠错:LLMs 并不是在预测下一个词
  • 【家政平台开发(21)】用户管理模块开发
  • 批量将 JSON 转换为 Excel/思维导入等其它格式
  • 人工智能起源:从图灵到ChatGPT
  • 4月6日随笔
  • 【注解小结】
  • ST 芯片架构全景速览:MCU、无线 SoC、BLE 模块、MPU 差异详解
  • MyBatis 分页插件使用教程
  • 如何做网课网站/搜索引擎外部优化有哪些渠道
  • 阿里云购买网站登录/长沙网络推广营销
  • 艺术类 网站建设方案/怎么去推广一个app
  • 网站建设的核心是/网络宣传的方法有哪些
  • 哪个网站建设公司/steam交易链接怎么看
  • 可以做展示页面的网站/手机系统流畅神器