设计模式之中介者模式(mediator模式)引入中介者模式中介者模式的实例中介者模式分析

  • 引入中介者模式
  • 中介者模式实例
  • 中介者模式分析

引入中介者模式

大家想象一下有十个人要共同完成一个工作,他们要互相合作和沟通,并且根据对方的通知可能要改变自己的状态,但这通常会带来很多问题,流程过于复杂,使得每个人不仅要专注于自己的事情,还要与他人进行沟通,得到通知,需要兼顾很多状态的变化。这时候,我们考虑可以引入一个类似上帝视角的角色,就是引入一个中介者,他来负责接受每个人的通知,并将变化发送所需要的人去,就是要他来控制并调节工作的进度和细节,这个人往往是从整体考虑的,所以使得每个人工作者只需要考虑自己的问题,一旦有了变化,就通知仲裁者,交给仲裁者去决定就可以了。 所以最后就变成了,整个团队的交流过程,组员向中介者报告,中介者向组员下达只命令。 这在现实生活中也是常见的,每个部门通常都会有一个领导人,每个班级有一个班长,往往是班长负责接受同学们的信息,然后将上面的信息从班长这里发给同学们,这里的班长就相当于一个仲裁者,同学们就相当于组员。

这就是中介者模式的基本思想,mediator有仲裁者和中介者的意思,一方面,当麻烦事情发生的时候,通知仲裁者,当发生设计全体组员的事情时,也通知仲裁者。当仲裁者下达指示的时候,组员会立即执行。团队组员之间不再互相沟通并私自做决定,而是发生任何事情都像仲裁者报告。另一方面,仲裁者在整个团队的角度上对组员报告的事情进行决定。

中介者模式的实例

我们通过一个gui程序来实现一个简单的仲裁者模式

image.png

看上图是一个我们经常见的登录框。通常登录框就设计很多状态的变化,比如我们这个例子就要实现如下的逻辑

首先,如果选择用户登录,那么用户名输入框处于启用状态,但密码输入框处于禁用状态,如下图

image.png

如果用户输入了用户名,密码框就启用,如下图

image.png

如果又删掉了用户名,那么密码又变回禁用状态

image.png

如果选择游客登录,就都处于禁用状态。

image.png

假设我们有这样的需求,那么我们应该如何编写程序呢? 最先的想法就是,每个控件分别分别接受相关控件的状态,根据不同的状态在改变自己的状态。这样做是可以实现功能的,但是假设这时候我们新加一个控件进来,那么由于这个逻辑分散在各个控件的代码中,所以我们修改起来非常麻烦,而且每个控件都充斥着状态控制的代码,很臃肿,控件应该专注于实现自己的逻辑。 因为这些控件都相互关联,相互制约的,全部耦合在一起。 根据面向对象的设计原则,我们应该尽量对象过度耦合,实现松耦合的状态。

于是,我们就可以利用中介者模式,每个控件发生了变化,我们就把变化发给中介者,中介者统一来处理,这样控件就只需要专注于自己的实现就行了。

首先看类图:

image.png

首先,定义Mediator接口

public interface Mediator {
    public abstract void createColleagues();
    public abstract void colleagueChanged();
}

定义Colleague接口

public interface Colleague {
    public abstract void setMediator(Mediator mediator);
    public abstract void setColleagueEnabled(boolean enabled);
}

实现三个colleague类:

import java.awt.Button;

public class ColleagueButton extends Button implements Colleague {
    private Mediator mediator;
    public ColleagueButton(String caption) {
        super(caption);
    }
    public void setMediator(Mediator mediator) {            // 保存Mediator
        this.mediator = mediator;
    }
    public void setColleagueEnabled(boolean enabled) {      // Mediator下达启用/禁用的指示 
        setEnabled(enabled);
    }
}
import java.awt.Checkbox;
import java.awt.CheckboxGroup;
import java.awt.event.ItemListener;
import java.awt.event.ItemEvent;

public class ColleagueCheckbox extends Checkbox implements ItemListener, Colleague {
    private Mediator mediator;
    public ColleagueCheckbox(String caption, CheckboxGroup group, boolean state) {  // 构造函数 
        super(caption, group, state);
    }
    public void setMediator(Mediator mediator) {            // 保存Mediator
        this.mediator = mediator;
    }
    public void setColleagueEnabled(boolean enabled) {      // Mediator下达启用/禁用指示
        setEnabled(enabled);
    }
    public void itemStateChanged(ItemEvent e) {             // 当状态发生变化时通知Mediator
        mediator.colleagueChanged();
    }
}
import java.awt.TextField;
import java.awt.Color;
import java.awt.event.TextListener;
import java.awt.event.TextEvent;

public class ColleagueTextField extends TextField implements TextListener, Colleague {
    private Mediator mediator;
    public ColleagueTextField(String text, int columns) {   // 构造函数
        super(text, columns);
    }
    public void setMediator(Mediator mediator) {            // 保存Mediator
        this.mediator = mediator;
    }
    public void setColleagueEnabled(boolean enabled) {      // Mediator下达启用/禁用的指示
        setEnabled(enabled);
        setBackground(enabled ? Color.white : Color.lightGray);
    }
    public void textValueChanged(TextEvent e) {             // 当文字发生变化时通知Mediator
        mediator.colleagueChanged();
    }
}

最后实现具体的中介者对象

import java.awt.Frame;
import java.awt.Label;
import java.awt.Color;
import java.awt.CheckboxGroup;
import java.awt.GridLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class LoginFrame extends Frame implements ActionListener, Mediator {
    private ColleagueCheckbox checkGuest;
    private ColleagueCheckbox checkLogin;
    private ColleagueTextField textUser;
    private ColleagueTextField textPass;
    private ColleagueButton buttonOk;
    private ColleagueButton buttonCancel;

    // 构造函数。
    // 生成并配置各个Colleague后,显示对话框。
    public LoginFrame(String title) {
        super(title);
        setBackground(Color.lightGray);
        // 使用布局管理器生成4×2窗格
        setLayout(new GridLayout(4, 2));
        // 生成各个Colleague
        createColleagues();
        // 配置
        add(checkGuest);
        add(checkLogin);
        add(new Label("Username:"));
        add(textUser);
        add(new Label("Password:"));
        add(textPass);
        add(buttonOk);
        add(buttonCancel);
        // 设置初始的启用起用/禁用状态
        colleagueChanged();
        // 显示
        pack();
        show();
    }

    // 生成各个Colleague。
    public void createColleagues() {
        // 生成
        CheckboxGroup g = new CheckboxGroup();
        checkGuest = new ColleagueCheckbox("Guest", g, true);
        checkLogin = new ColleagueCheckbox("Login", g, false);
        textUser = new ColleagueTextField("", 10);
        textPass = new ColleagueTextField("", 10);
        textPass.setEchoChar('*');
        buttonOk = new ColleagueButton("OK");
        buttonCancel = new ColleagueButton("Cancel");
        // 设置Mediator
        checkGuest.setMediator(this);
        checkLogin.setMediator(this);
        textUser.setMediator(this);
        textPass.setMediator(this);
        buttonOk.setMediator(this);
        buttonCancel.setMediator(this);
        // 设置Listener
        checkGuest.addItemListener(checkGuest);
        checkLogin.addItemListener(checkLogin);
        textUser.addTextListener(textUser);
        textPass.addTextListener(textPass);
        buttonOk.addActionListener(this);
        buttonCancel.addActionListener(this);
    }

    // 接收来自于Colleage的通知然后判断各Colleage的启用/禁用状态。
    public void colleagueChanged() {
        if (checkGuest.getState()) { // Guest mode
            textUser.setColleagueEnabled(false);
            textPass.setColleagueEnabled(false);
            buttonOk.setColleagueEnabled(true);
        } else { // Login mode
            textUser.setColleagueEnabled(true);
            userpassChanged();
        }
    }
    // 当textUser或是textPass文本输入框中的文字发生变化时
    // 判断各Colleage的启用/禁用状态
    private void userpassChanged() {
        if (textUser.getText().length() > 0) {
            textPass.setColleagueEnabled(true);
            if (textPass.getText().length() > 0) {
                buttonOk.setColleagueEnabled(true);
            } else {
                buttonOk.setColleagueEnabled(false);
            }
        } else {
            textPass.setColleagueEnabled(false);
            buttonOk.setColleagueEnabled(false);
        }
    }
    public void actionPerformed(ActionEvent e) {
        System.out.println(e.toString());
        System.exit(0);
    }
}

Main类

import java.awt.*;
import java.awt.event.*;

public class Main {
    static public void main(String args[]) {
        new LoginFrame("Mediator Sample");
    }
}

运行结果

image.png

中介者模式分析

中介者模式主要有几个角色

  • 中介者 就是负责定义控制逻辑,接受来自组员的消息并处理的接口,对应实例中的Mediator接口
  • 具体的中介者 实现接口,并根据不同的需求,做出不同的逻辑
  • 同事组员Colleague 组员的接口,定义相应的方法
  • 具体的组员 负责实现具体的组员逻辑,并将通知直接交给中介者执行

中介者模式的类图:

image.png

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏ChaMd5安全团队

N1CTF2018 APFS&Lipstick题解

APFS题目描述 Apple released the brand new APFS on WWDC 2017 with a bunch of new feat...

35810
来自专栏简书专栏

Python数据持久化-csv、excel篇

2018年7月4日笔记 学习目标: 1.会使用Python第三方模块操作CSV文件 2.会使用Python第三方模块操作EXCEL文件

1812
来自专栏互联网杂技

react+redux+webpack教程3

现代web页面里到处都是ajax,所以处理好异步的代码非常重要。 这次我重新选了个最适合展示异步处理的应用场景——搜索新闻列表。由于有现成的接口,我们就不用自己...

42910
来自专栏小巫技术博客

Android触摸事件机制

1163
来自专栏源哥的专栏

SaaS行业命名规范

    很多企业在启动软件开发的时候,完成没有命名规范,导致代码的可读性极差。而业界对于命名,却没有一个统一的命名规范,比如说,获取客户列表,Java类的方法是...

1943
来自专栏MixLab科技+设计实验室

设计师编程指南之Sketch插件开发 4

为什么写这个系列的文章,一是因为网上相关的 sketch 插件开发教程太少,官方的文档写得不算太清楚,二是因为本公众号长期在研究智能设计相关的内容,基于 ske...

3528
来自专栏雪胖纸的玩蛇日常

Vue+Django2.0 REST framework打造前后端分离的生鲜电商项目(三)设计数据库以及导入原始数据

4885
来自专栏SAP最佳业务实践

SAP最佳业务实践:MM–组件收费的委外加工(251)-6开销售发票

4.7 创建出具发票凭证 创建出具发票凭证给委外加工商。 完成了对委外加工商的发货。 SAP ECC菜单Processes -Create Invoices f...

4178
来自专栏杨建荣的学习笔记

dg的奇怪问题终结和分区问题答疑 (r7笔记第77天)

今天来说几个问题,一个是对昨天《让我焦灼的四个问题》的升华,不能起博眼球的题目,技术分析给大家兜底了,你们看看有没有类似的问题。 还有几个小问题说说今天的感受和...

3525
来自专栏杨建荣的学习笔记

巧用parallel极速提升数据加载速度(r2第21天)

并行在平时工作中可能不是很注意,因为有时候即使设定了parallel 相关的hint,感觉性能也好不到哪去。这是我以前的感觉。 今天通过一个案例来分享一下通过p...

3586

扫码关注云+社区

领取腾讯云代金券