前言
温故而知新
先复习前面学到的行为型模式:
- 模板方法模式:定义一个算法、流程骨架,将特定步骤的实现延迟到子类,完成模板的复用(请客流程:点单 -》吃 -》买单,具体吃什么可以由子类决定)
- 命令模式:将命令封装成对象,聚合执行者,使请求者仅需使用命令对象即可完成命令,执行者与请求者完全解耦合(遥控器上的按钮就是一个个命令对象,遥控器仅需按下按钮即可完成开关灯命令)
- 访问者模式:将施加于对象结构的元素上的操作隔离,封装成访问者,对象结构提供访问者访问的接口,即修改访问者不会影响到对象结构(购物车就是一个对象结构,上面的各个商品是各种元素对象,顾客访问者可以查看质量,收银员可以查看价格)
- 迭代器模式:将聚合对象中数据对象的存储与遍历功能分隔,遍历功能封装成迭代器,聚合对象工厂方法创建相对应的迭代器(Linux目录用迭代器描述目录结构)
- 观察者模式:定义对象间的一对多的依赖关系,当对象状态改变时,会自动通知所有依赖的对象并自动更新对象数据(气象局天气数据改变,各网站天气数据也改变)
接下来,学习中介者模式
现实中的问题
现实中,对象间的交互关系一般是网状结构,每个对象都必须知道它需要交互的对象,例如,你电话号换了,需要通知父母、亲人、同学自己电话换了,对应如果软件也是这样的,就会十分的复杂
例如QQ聊天,如果真的要你的电脑与聊天对象的电脑连接,需要知道IP地址,聊天对象也需要知道我们的地址才能发信息给我们
如果这样就太复杂了,现实是我们是发送消息给QQ的服务器,QQ服务器再找到我们的聊天对象的IP地址,把消息发送过去
服务器就是一个中介者,它把对象间的网状关系变成了星形结构
中介模式
什么是中介者模式?
中介者模式(Mediator Pattern):用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式
为什么要中介者模式?
在面向对象的软件设计与开发过程中,根据“单一职责原则”,我们应该尽量将对象细化,使其只负责或呈现单一的职责
对于一个模块,可能由很多对象构成,而且这些对象之间可能存在相互的引用,为了减少对象两两之间复杂的引用关系,使之成为一个松耦合的系统,我们需要使用中介者模式
模式结构
模式角色:
- 抽象中介者(Mediator)角色:它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法
- 具体中介者(ConcreteMediator)角色:实现中介者接口,定义一个集合来管理同事对象,协调各个同事角色之间的交互关系,因此它依赖于同事角色。
- 抽象同事类(Colleague)角色:定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能
- 具体同事类(Concrete Colleague)角色:是抽象同事类的实现者,当需要与其他同事对象交互时,由中介者对象负责后续的交互
模式实现案例
简单描述一下QQ群聊的过程
小明发送信息,小红能够收到
package com.company.Behavioral.Mediator;
import java.util.ArrayList;
import java.util.List;
//抽象中介者
abstract class Mediator {
public abstract void register(Colleague colleague);
public abstract void forward(Colleague colleague);
}
//具体中介者
class QQServer extends Mediator{
private List<Colleague> colleaguelist;
public QQServer() {
this.colleaguelist = new ArrayList<Colleague>();
}
@Override
public void register(Colleague colleague) {
colleaguelist.add(colleague);
//注册时,把中介者聚合到同事类
colleague.setMediator(this);
}
@Override
public void forward(Colleague colleague) {
for (Colleague colleague1 : colleaguelist){
//转发给除自己外的注册在服务器上的人
if (!colleague.equals(colleague1)){
colleague1.receive();
}
}
}
}
//抽象同事类
abstract class Colleague{
protected Mediator mediator;
public void setMediator(Mediator mediator) {
this.mediator = mediator;
}
public abstract void receive();
public abstract void send();
}
//具体同事类小明
class XiaoMing extends Colleague{
@Override
public void receive() {
System.out.println("====小明接收到了信息====");
}
@Override
public void send() {
System.out.println("====小明发送信息====");
mediator.forward(this);
}
}
//具体同事类:小红
class XiaoHong extends Colleague{
@Override
public void receive() {
System.out.println("====小红接收到了信息====");
}
@Override
public void send() {
System.out.println("====小红发送信息====");
mediator.forward(this);
}
}
class Test{
public static void main(String[] args) {
//创建具体同事类
Colleague xiaoHong = new XiaoHong();
Colleague xiaoMing = new XiaoMing();
//创建中介者
Mediator qqServer = new QQServer();
//注册
qqServer.register(xiaoHong);
qqServer.register(xiaoMing);
//小明发送信息
xiaoMing.send();
}
}
这里QQ服务器类转发功能只是简单处理了一下
模式分析
- 中介模式将对象间复杂的网状结构关系改变成了星型结构关系
- 中介者承担了两个职责:
中转作用(结构性):通过中介者提供的中转作用,各个同事对象就不再需要显式引用其他同事,当需要和其他同事进行通信时,通过中介者即可。该中转作用属于中介者在结构上的支持
协调作用(行为性):中介者可以更进一步的对同事之间的关系进行封装,同事可以一致地和中介者进行交互,而不需要指明中介者需要具体怎么做,中介者根据封装在自身内部的协调逻辑,对同事的请求进行进一步处理,将同事成员之间的关系行为进行分离和封装。该协调作用属于中介者在行为上的支持
模式优缺点
优点
- 简化了对象之间的交互
- 将各同事解耦
- 减少子类生成
- 可以简化各同事类的设计和实现
缺点
解耦合一般付出的代价就是系统复杂度的提高
在具体中介者类中包含了同事之间的交互细节,可能会导致具体中介者类非常复杂,使得系统难以维护
中介者模式类似与把同事类间的耦合全部集中在中介者上,导致中介者的复杂度提高
适用环境
- 系统中对象之间存在复杂的引用关系,产生的相互依赖关系结构混乱且难以理解
- 一个对象由于引用了其他很多对象并且直接和这些对象通信,导致难以复用该对象
- 想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。可以通过引入中介者类来实现,在中介者中定义对象交互的公共行为,如果需要改变行为则可以增加新的中介者类
模式扩展
- 应用
中介者模式使用也较多
MVC模式是Java EE 的一个基本模式,此时控制器Controller作为一种中介者,它负责控制视图对象View和模型对象Model之间的交互
- 简化
不定义抽象中介者,使用单例模式具体中介者(一个关系中,中介者一般是只有一个的)
同事对象不持有中介者,而是在需要的时直接获取中介者对象并调用(配合单例模式)
- 迪米特法则
迪米特法则:限制软件实体之间通信的宽度和深度
中介者模式将同事类间的关联关系减少,符合迪米特法则
总结
- 中介者模式是用一个中介对象封装对象间的一系列的交互,消除对象间的显示引用,松散耦合
- 中介者模式有4个角色:抽象中介者、具体中介者、抽象同事类、具体同事类
- 抽象中介者定义与各个同事对象间的通信;具体中介者协调各个同事类实现协作行为,维护对各个同事对象的引用;抽象同事类定义对中介者的通信方法;具体同事类实现与中介者的通信间接完成与其他同事类的通信
- 中介者模式优点:简化了对象间的交互,简化了同事类的设计与实现;缺点:具体中介类复杂,难以维护
- 中介者将系统的网状结构变成了星型结构,中介者承担了中转作用和协调作用
- 中介者模式适用于:对象间存在复杂的引用关系、相互依赖关系;想通过一个中间类封装多个类的行为
- 中介者模式实际使用一般都是不使用抽象中介者,具体中介者使用单例模式,同事类不聚合中介者,仅使用时调用中介者方法