简介
为什么要使用中介者模式
举个例子,在设计聊天软件或类似的软件时,用户对象和用户对象之间存在着多对多的关系,这将导致系统出现过于复杂,扩展性低,可用性差等问题。中介者模式可以解决类似问题。中介者模式将对象之间的关联关系剥离出来,并封装在“中介者”对象中,由“中介者”对象来统一协调。这样多对多的关系就变成了一对多的关系。中介者模式是“迪米特法则”的典型应用。
什么是中介者模式
中介者模式(Mediator Pattern):用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
别名
调停者模式
类型
对象行为型模式
使用频率
★★☆☆☆
遵循的原则
迪米特法则、开闭原则
角色
角色
- Mediator: 抽象中介者
- 抽象类
- 具体中介者的父类。
- 定义一个接口用于与各同事通信。
- ConcreteMediator: 具体中介者
- 具体类
- 抽象中介者的子类。
- 含有对各个同事对象的引用,协调各个同事对象。
- Colleague: 抽象同事类
- 抽象类
- 具体同事类的父类。
- 维持了对抽象中介者的引用,具体中介者可以通过这个引用和中介者通信。
- ConcreteColleague: 具体同事类
- 具体类
- 抽象同事类的子类。
- 每一个同事对象在需要和其他同事对象通信时,先与中介者通信,通过中介者来间接完成与其他同事类的通信。
UML类图
实现
- 新建抽象中介者Mediator.java
- 新建具体中介者ConcreteMediator.java
- 新建抽象同事类Colleague.java
- 新建具体同事类ConcreteColleagueA.java,ConcreteColleagueB.java
- 新建客户端类Client.java
抽象中介者
Mediator.java
import java.util.ArrayList;
abstract class Mediator {
protected ArrayList<Colleague> colleagues; // 用于存储同事对象。不一定是ArrayList类型,什么类型根据具体需求定。
// 注册方法,用于增加同事对象
public void register(Colleague colleague) {
colleagues.add(colleague);
}
// 声明抽象的业务方法,供同事对象调用
public abstract void operation();
}
具体中介者
ConcreteMediator.java
class ConcreteMediator extends Mediator {
// 实现业务方法,封装同事之间的联系与调用。根据具体需求编写代码
public void operation() {
// ......
((Colleague) (colleagues.get(0))).sendmsg(); // 通过中介者调用同事类的方法
// ......
}
}
抽象同事类
Colleague.java
abstract class Colleague {
protected Mediator mediator; // 维持一个抽象中介者的引用。以供调用中介者。
public Colleague(Mediator mediator) {
this.mediator = mediator;
}
public abstract void receivemsg(); // 声明方法,处理自己的行为
// 定义依赖方法,与中介者进行通信。根据具体需求编写代码
public void sendmsg() {
mediator.operation();//与中介者进行通信
}
}
具体同事类
ConcreteColleagueA.java
class ConcreteColleagueA extends Colleague {
public ConcreteColleagueA(Mediator mediator) {
super(mediator);
}
@Override
public void receivemsg() {
//根据具体需求编写代码
}
}
ConcreteColleagueB.java
class ConcreteColleagueB extends Colleague {
public ConcreteColleagueB(Mediator mediator) {
super(mediator);
}
@Override
public void receivemsg() {
//根据具体需求编写代码
}
}
客户端类
Client.java
public class Client {
public static void main(String[] args) {
//创建中介者
ConcreteMediator cm = new ConcreteMediator();
//创建同事对象
ConcreteColleagueA cca = new ConcreteColleagueA(cm);
ConcreteColleagueB ccb = new ConcreteColleagueB(cm);
//注册同事对象进中介者
cm.register(cca);
cm.register(ccb);
//调用方法,进行同事之间的通信
cca.sendmsg();
}
}
实例1:聊天软件
UML类图
角色
- Mediator: 抽象聊天中心
- 抽象类
- 具体中介者的父类
- ConcreteMediator: 具体聊天中心
- 具体类
- 抽象中介者的子类
- 支持群发,两人对话
- Colleague: 抽象用户类
- 抽象类
- 具体用户类的父类
- ConcreteColleague: 用户类
- 具体类
- 抽象用户类的子类
- 每一个用户对象在需要和其他用户对象通信时,先与聊天中心通信,通过聊天中心来间接完成与其他用户类的通信
代码
- 新建抽象聊天中心Mediator.java
- 新建具体聊天中心ConcreteMediator.java
- 新建抽象用户类Colleague.java
- 新建用户类ConcreteColleagueA.java,ConcreteColleagueB.java,ConcreteColleagueC.java
- 新建测试Client.java
抽象聊天中心
Mediator.java
import java.util.HashMap;
import java.util.Map;
abstract class Mediator {
protected Map<String, Colleague> colleagues = new HashMap<String, Colleague>(); // 用于存储同事对象
// 注册方法,用于增加同事对象
public void register(String str, Colleague colleague) {
colleagues.put(str, colleague);
}
// 声明抽象的业务方法:群发消息
public abstract void operation(Colleague colleague, String str);
// 声明抽象的业务方法:两人对话
public abstract void operation(Colleague colleague, String key, String str);
}
具体聊天中心
ConcreteMediator.java
class ConcreteMediator extends Mediator {
// 实现业务方法,群发消息
public void operation(Colleague colleague, String str) {
for (String key : colleagues.keySet()) {
if (!(colleagues.get(key) == colleague))
colleagues.get(key).receivemsg(colleague, str);
}
}
// 实现业务方法,两人对话
public void operation(Colleague colleague, String key, String str) {
colleagues.get(key).receivemsg(colleague, str);
}
}
抽象用户类
Colleague.java
abstract class Colleague {
protected Mediator mediator; // 维持一个抽象中介者的引用
public Colleague(Mediator mediator) {
this.mediator = mediator;
}
// 群发消息
public void sendmsg(String str) {
System.out.println(this.getClass().getSimpleName().toString() + " sendmsg:\n" + str);
mediator.operation(this, str);
}
// 两人对话
public void sendmsg(String key, String str) {
System.out.println(this.getClass().getSimpleName().toString() + " sendmsg to " + key + ":\n" + str);
mediator.operation(this, key, str);
}
//接收消息
public void receivemsg(Colleague colleague, String str) {
System.out.println(this.getClass().getSimpleName().toString() + " receivemsg:\n"
+ colleague.getClass().getSimpleName() + ":" + str);
}
}
用户类
ConcreteColleagueA.java
class ConcreteColleagueA extends Colleague {
public ConcreteColleagueA(Mediator mediator) {
super(mediator);
}
}
ConcreteColleagueB.java
class ConcreteColleagueB extends Colleague {
public ConcreteColleagueB(Mediator mediator) {
super(mediator);
}
}
ConcreteColleagueC.java
class ConcreteColleagueC extends Colleague {
public ConcreteColleagueC(Mediator mediator) {
super(mediator);
}
}
测试类Client.java
public class Client {
public static void main(String[] args) {
//创建中介者
ConcreteMediator cm = new ConcreteMediator();
//创建同事
ConcreteColleagueA cca = new ConcreteColleagueA(cm);
ConcreteColleagueB ccb = new ConcreteColleagueB(cm);
ConcreteColleagueC ccc = new ConcreteColleagueC(cm);
//注册同事进中介者
cm.register("cca", cca);
cm.register("ccb", ccb);
cm.register("ccc", ccc);
// 群发消息
cca.sendmsg("Hello,I'm A");
System.out.println("----------------------------");
// 两个对象之间的通话
cca.sendmsg("ccb", "Hello,I'm A");
}
}
测试
运行Client.java的main()
ConcreteColleagueA sendmsg:
Hello,I'm A
ConcreteColleagueC receivemsg:
ConcreteColleagueA:Hello,I'm A
ConcreteColleagueB receivemsg:
ConcreteColleagueA:Hello,I'm A
----------------------------
ConcreteColleagueA sendmsg to ccb:
Hello,I'm A
ConcreteColleagueB receivemsg:
ConcreteColleagueA:Hello,I'm A
优缺点
优点
- 遵守“迪米特法则”。中介者模式将各同事解耦,实现了“一个对象应当对其他对象保持最少的了解”。
- 遵守“开闭原则”。
- 如果需要引入新的具体同事类,只需要继承抽象同事类并实现其中的方法即可,由于具体同事类之间并无直接的引用关系,因此原有所有同事类无须进行任何修改,它们与新增同事对象之间的交互可以通过修改或者增加具体中介者类来实现;
- 如果需要增加新的具体中介者类,只需要继承抽象中介者类(或已有的具体中介者类)并覆盖其中定义的方法即可,在新的具体中介者中可以通过不同的方式来处理对象之间的交互,也可以增加对新增同事的引用和调用。
缺点
- 中介者类包含了各同事类的关联细节,可能会非常复杂,难以维护。
适用环境
- 一组对象以定义良好但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。
- 一个对象引用其他很多对象并且直接与这些对象通信。
使用场景
- GUI开发。
扩展
- 外观模式Facade与中介者的不同之处在于它是对一个对象子系统进行抽象,从而提供一个更方便的接口。中介者模式Mediator是将colleague之间的关联封装到中介者中,colleague通过中介者进行通讯,从而为colleague之间的访问提供了一个接口。
- Colleague可使用观察者模式Observer与Mediator通信。
问题
在软件开发中,你在哪里用到了中介者模式?
待补充。