Mediator模式简介

Mediator模式即中介者模式,可以像租房中介一样对比理解。

模式来源:比如一个窗口程序里面包含按钮、复选框、文本框等角色,他们之间的状态可能相互关联:比如你必须勾选同意用户协议的复选框才能进行点击下一步按钮,即复选框同意按钮有关联关系。像这样的同一个页面有关联关系的部件可能很多,关联关系可能很复杂。如果这些按钮既要负责自己的显示,又要负责维护关联关系,职责就太多了,极易发生混乱而出错。

此模式的关键作用是:职责分离,把各个部件中负责关联关系的部分提取出来,由一个中介统一管理。

示例程序

一个登录对话框,如图所示

使用方式如下

各种情况

  • 作为游客访问,禁用用户名和密码输入框

  • 作为用户登录,启用用户名输入框,如果没有输入用户名,则不启用密码框

  • 用户登录时,如果输入了用户名,则启用密码框

  • 用户登录时,如果用户名和密码的字符串长度都超过了4个字符,则OK按钮启用,否则不启用

  • Cancel按钮总是处于启用状态

示例程序类图

  • Mediator是中介者接口,Colleague是组员接口,组员之间的关系由中介者维护。

代码

Mediator接口

这个接口是中介者的抽象接口,具体的中介者会继承并实现它

public interface Mediator {
//生成组员方法
public abstract void createColleagues();
//组员状态改变后向中介报告
public abstract void colleagueChanged();
}

Colleague接口

此接口是组员的抽象接口,具体的组员接口实现它。

  • setMediator(Mediator mediator):设置中介。具体的组员内部会引用一个中介者,这个方法用来设置中介者。
  • setColleagueEnabled(boolean enabled):设置组员自己的状态。这个方法被中介者调用进而控制组员,enabled为true表示组员可用,否则表示组员不可用。
public interface Colleague {
//设置中介
public abstract void setMediator(Mediator mediator);
//设置自己的状态是(可用/不可用)
public abstract void setColleagueEnabled(boolean enabled);
}

三个具体的Colleague

  • checkbox和textfield变化时需要通知中介,button不需要。
  • 每个组员有一份中介的引用,用于向中介报告自己的状态。
//checkbox
public class ColleagueCheckbox extends Checkbox implements ItemListener, Colleague {
private Mediator mediator;
public ColleagueCheckbox(String caption, CheckboxGroup group, boolean state) {
// 构造函数
super(caption, group, state);
}
@Override
public void itemStateChanged(ItemEvent e) { // 当状态发生变化时通知Mediator
mediator.colleagueChanged();
}
@Override
public void setMediator(Mediator mediator) { // 保存Mediator
this.mediator = mediator;
}
@Override
public void setColleagueEnabled(boolean enabled) { // Mediator下达启用/禁用指示
setEnabled(enabled);
}
} //textfield
public class ColleagueTextField extends TextField implements TextListener, Colleague {
private Mediator mediator;
public ColleagueTextField(String text, int columns) { // 构造函数
super(text, columns);
}
@Override
public void setMediator(Mediator mediator) { // 保存Mediator
this.mediator = mediator;
}
@Override
public void setColleagueEnabled(boolean enabled) { // Mediator下达启用/禁用的指示
setEnabled(enabled);
setBackground(enabled ? Color.white : Color.DARK_GRAY);
}
@Override
public void textValueChanged(TextEvent e) { // 当文字发生变化时通知Mediator
mediator.colleagueChanged();
}
}
//button
public class ColleagueButton extends Button implements Colleague {
private Mediator mediator;
public ColleagueButton(String caption) {
super(caption);
}
@Override
public void setMediator(Mediator mediator) { // 保存Mediator
this.mediator = mediator;
}
@Override
public void setColleagueEnabled(boolean enabled) { // Mediator下达启用/禁用的指示
setEnabled(enabled);
}
}

具体的中介者

本例中的中介包含了两个功能:1.生成组员 2.接收组员的通知并采取相应措施。

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.LIGHT_GRAY);
// 使用布局管理器生成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。
@Override
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("Confirm");
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);
} @Override
public void colleagueChanged() {
//游客模式:用户名密码都不可填
if (checkGuest.getState()) {
textUser.setColleagueEnabled(false);
textPass.setColleagueEnabled(false);
buttonOk.setColleagueEnabled(true);
}
// 用户登录模式:用户名可填写,根据用户名文本框里填写的内容来确定 密码框和按钮 是否可用
else {
textUser.setColleagueEnabled(true);
userpassChanged();
}
} private void userpassChanged() {
//如果填写了用户名
if (textUser.getText().length() > 0) {
//可以填写密码
textPass.setColleagueEnabled(true);
//如果用户名和密码都超过了4个字符,符合要求,确认按钮才能启用
if (textUser.getText().length() >= 4 && textPass.getText().length() >= 4) {
buttonOk.setColleagueEnabled(true);
} else {
buttonOk.setColleagueEnabled(false);
}
}
//如果没有填写用户名,则密码和确定按钮都不显示
else {
textPass.setColleagueEnabled(false);
buttonOk.setColleagueEnabled(false);
}
}
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("动作是:" + e.getActionCommand());
System.exit(0);
}
}

main函数

public class Main {
static public void main(String args[]) {
new LoginFrame("中介者模式");
}
}

Mediator模式角色和类图

角色

  • Mediator 中介者角色,负责定义与Colleague角色进行通信和做出决定的接口。

  • ConcreteMediator 具体的中介者角色,实现Mediator角色的接口,负责做出决定。

  • Colleague 负责定义与Mediator进行通信的接口。

  • ConcreteColleague 负责实现Colleague定义的接口。

模式类图

思路拓展

简单化

这个模式最大的好处就是通过职责分离,将组件的显示逻辑控制分离。在组件数量少的时候,关联关系简单,中介者的代码看起来很麻烦,似乎没有必要,但一旦需求变更,组件的数量增加,它们之间的通信线路就会呈指数增长,复杂度大大增加。使用中介作为逻辑控制中心,增加功能和维护功能都会变得很容易。

角色复用

如果不使用中介者模式,显示和逻辑混在一起,很难复用。

但实际上只是具体的业务逻辑难以被复用,显示用的组件是可以被复用的。

所以该模式把两部分拆出来,为组件的复用提供了便利。

《图解设计模式》读书笔记7-2 Mediator模式的更多相关文章

  1. HeadFirst设计模式读书笔记(3)-装饰者模式(Decorator Pattern)

    装饰者模式:动态地将责任附件到对象上.若要扩展功能,装饰者提东了比继承更有弹性的替代方案. 装饰者和被装饰对象有相同的超类型 你可以用一个或者多个装饰者包装一个对象. 既然装饰者和被装饰对象有相同的超 ...

  2. HeadFirst设计模式读书笔记--目录

    HeadFirst设计模式读书笔记(1)-策略模式(Strategy Pattern) HeadFirst设计模式读书笔记(2)-观察者模式(Observer Pattern) HeadFirst设计 ...

  3. Head First 设计模式读书笔记(1)-策略模式

    一.策略模式的定义 策略模式定义了算法族,分别封装起来,让它们之间可以互换替换,此模式让算法的变化独立使用算法的客户. 二.使用策略模式的一个例子 2.1引出问题 某公司做了一套模拟鸭子的游戏:该游戏 ...

  4. JavaScript设计模式:读书笔记(未完)

    该篇随我读书的进度持续更新阅读书目:<JavaScript设计模式> 2016/3/30 2016/3/31 2016/4/8 2016/3/30: 模式是一种可复用的解决方案,可用于解决 ...

  5. 图解http读书笔记

    以前对HTTP协议一知半解,一直不清楚前端需要对于HTTP了解到什么程度,知道接触的东西多了,对于性能优化.服务端的配合和学习中也渐渐了解到了HTTP基础的重要性,看了一些大神对HTTP书籍的推荐,也 ...

  6. Java设计模式学习笔记(二) 简单工厂模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 正文开始... 1. 简介 简单工厂模式不属于GoF23中设计模式之一,但在软件开发中应用也较为 ...

  7. Java设计模式学习笔记(三) 工厂方法模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 简介 上一篇博客介绍了简单工厂模式,简单工厂模式存在一个很严重的问题: 就是当系统需要引入 ...

  8. Java设计模式学习笔记(四) 抽象工厂模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 抽象工厂模式概述 工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问 ...

  9. C#设计模式学习笔记:(23)解释器模式

    本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/8242238.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第十一个模式-- ...

  10. 设计模式(十六)Mediator模式

    在实际的工作小组的交流过程是,组员向仲裁者报告,仲裁者向组员下达指示,组员之间不再互相询问和指示.Mediator模式是指,当发生麻烦事情的时候,通知仲裁者:当发生涉及全体组员的事情时,也通知仲裁者. ...

随机推荐

  1. IBM公司的面试题,看看你能做出多少。

    进入IBM差不多是每一个IT人的梦想.IBM公司向来以高素质人才作为企业持续竞争力的保证,所以经常出一些千奇百怪的面试题,来考验一个人的综合能力,以下是5道IBM曾经出过的面试题,看看你能作出几道:  ...

  2. 基于Nginx+nginx-rtmp-module+ffmpeg搭建rtmp、hls流媒体服务器(二)

    前言 Nginx-rtmp-module插件针对RTMP协议中一些命令,实现了事件通知和exec外部脚本处理.这里我通过一个简单的SpringBoot项目和Python代码,快速搭建一个HTTP服务来 ...

  3. Ant Design -- 图片可拖拽效果,图片跟随鼠标移动

    Ant Design 图片可拖拽效果,图片跟随鼠标移动,需计算鼠标在图片中与图片左上角的X轴的距离和鼠标在图片中与图片左上角的Y轴的距离. constructor(props) { super(pro ...

  4. tp5 模板参数配置(模板静态文件路径)

    tp5 模板参数配置(模板静态文件路径) // 模板页面使用 <link rel="stylesheet" type="text/css" href=&q ...

  5. vim 修改复制过来的代码缩进

    命令模式下 :1,9<  //1至9行回退一个tab :1,9> //1至9行缩进一个tab 让不可打印字符心事出来::set list

  6. js 调试接口

    在我们做完前端的工作后,很多情况下需要把我们的数据与后端得接口进行对接,说以我们就得掌握调试接口的方法 一.建立对象数组(一般是后端的工作) 代码如下: [ {"name":&qu ...

  7. 【GDOI2014模拟】网格

    题目 某城市的街道呈网格状,左下角坐标为A(0, 0),右上角坐标为B(n, m),其中n >= m.现在从A(0, 0)点出发,只能沿着街道向正右方或者正上方行走,且不能经过图示中直线左上方的 ...

  8. 【rust】Rust变量绑定(3)

    Rust 是一个静态类型语言,这意味着我们需要先确定我们需要的类型. 什么是变量绑定? 将一些值绑定到一个名字上,这样可以在之后使用他们. 如何声明一个绑定? 使用 let 关键字: fn main( ...

  9. Comet OJ - Contest #4 D求和 思维题

    Code: #include <bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) ...

  10. Spring——简介

    学习网站: [1]http://spring.io/ [2]http://projects.spring.io/spring-framework/ Spring是为解决企业应用开发的复杂性而创建的,是 ...