23种设计模式之中介者模式
参考资料
- Java设计模式:23种设计模式全面解析(超级详细)
- 韩顺平老师的Java设计模式(图解+框架源码剖析)
- 秦小波老师的《设计模式之禅》
下文如有错漏之处,敬请指正
一、简介
定义
定义一个中介对象来封装原有对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。即将多对多依赖关系转为一对多,其中一就是中介者。
特点
- 中介者模式是一种行为型模式
通用类图
在建造者模式中,有如下4个角色:
-
Mediator
抽象中介者角色
用于各同事角色之间的通信。 -
ConcreteMediator
具体中介者角色
实现中介者的抽象方法,定义一个集合来管理同事角色,协调各个同事角色之间的交互关系,因此它依赖于同事角色。 -
Colleague
抽象同事角色
保存中介者对象,提供同事角色交互的抽象方法,实现所有相互影响的同事角色的公共功能。 -
ConcreteColleague
具体同事角色
实现同事的抽象方法,当需要与其他同事对象交互时,由中介者对象负责后续的交互。
优点
- 降低了对象之间的耦合性,使得对象易于独立和复用。
- 将对象间的多对多的依赖关系转变为一对多的依赖关系,提高系统的灵活性,使得系统易于维护和扩展。
缺点
- 当同事类太多时,中介者的职责将很大,它会变得复杂而庞大,以至于系统难以维护。
应用场景
-
当对象之间存在复杂的网状结构关系而导致依赖关系混乱且难以复用时,考虑使用中介者模式,把网状结构梳理为星型结构,使原本复杂混 乱的关系变得清晰简单。
-
当想创建一个运行于多个类之间的对象,又不想生成新的子类时。
-
MVC框架
MVC框架,其中的C(Controller)就是一个中介者,叫做前端控制器(Front Controller),它的作用就是把M(Model,业务逻辑)和V(View,视图)隔离开,协调M和V协同工作,把M运行的结果和V代表的视图融合成一个前端可以展示的页面,减少M和V的依赖关系。
二、分类
- 标准中介者模式
- 简单中介者模式
- 不定义中介者接口,把具体中介者对象实现为单例,通过静态方法返回中介者对象。
- 同事对象不持有中介者,而是在需要的时通过静态方法获取。
标准中介者
需求:
目前有一个群发功能,用户可以给除自己以外的好友群发消息(且可以屏蔽某个好友),现在使用中介者模式实现这一功能。
抽象中介者:
package mediator.standard;
public abstract class Mediator {
// 注册
public abstract void register(Colleague colleague);
// 转发
public abstract void send(Colleague colleague, String message);
}
具体中介者:
package mediator.standard;
import java.util.ArrayList;
import java.util.List;
public class ConcreteMediator extends Mediator {
private List<Colleague> colleagues = new ArrayList<>();
@Override
public void register(Colleague colleague) {
if (!colleagues.contains(colleague)) {
colleagues.add(colleague);
// 给同事对象设置中介者对象
colleague.setMediator(this);
}
}
@Override
public void send(Colleague colleague, String message) {
// 实现群发功能
for (Colleague user : colleagues) {
if (!user.equals(colleague)) {
// 模拟赵六不是任何人的朋友,即赵六接收不到任何人的消息
if (user.getUserName() != "赵六") {
user.receive(message);
}
}
}
}
}
抽象同事类:
package mediator.standard;
public abstract class Colleague {
private String userName;
public Colleague(String userName) {
this.userName = userName;
}
public String getUserName() {
return userName;
}
protected Mediator mediator;
public void setMediator(Mediator mediator) {
this.mediator = mediator;
}
public abstract void receive(String message);
public abstract void send(String message);
}
具体同事类:
package mediator.standard;
public class ConcreteColleague extends Colleague {
public ConcreteColleague(String userName) {
super(userName);
}
@Override
public void receive(String message) {
System.out.println(this.getUserName() + "收到了消息,消息内容是:" + message);
}
@Override
public void send(String message) {
System.out.println(this.getUserName() + "群发消息,消息内容是:" + message);
mediator.send(this, message);
}
}
Client:
package mediator.standard;
public class Client {
public static void main(String[] args) {
// 创建4个用户,其中3个用户直接是好友关系,而用户姓名为赵六的没有好友
Colleague user1 = new ConcreteColleague("赵六");
Colleague user2 = new ConcreteColleague("张三");
Colleague user3 = new ConcreteColleague("李四");
Colleague user4 = new ConcreteColleague("王五");
// 创建中介者,并向其注册同事对象
Mediator mediator = new ConcreteMediator();
mediator.register(user1);
mediator.register(user2);
mediator.register(user3);
mediator.register(user4);
// 模拟用户给好友群发消息
user2.send("新年快乐!");
System.out.println("============");
user3.send("祝大家新年快乐!");
/**
* 输出结果:
* 张三群发消息,消息内容是:新年快乐!
* 李四收到了消息,消息内容是:新年快乐!
* 王五收到了消息,消息内容是:新年快乐!
* ============
* 李四群发消息,消息内容是:祝大家新年快乐!
* 张三收到了消息,消息内容是:祝大家新年快乐!
* 王五收到了消息,消息内容是:祝大家新年快乐!
*/
}
}
简单中介者
具体中介者:
package mediator.simple;
import java.util.ArrayList;
import java.util.List;
public class Mediator {
private static Mediator mediator = new Mediator();
private List<Colleague> colleagues = new ArrayList<>();
private Mediator() {
}
public static Mediator getMediator() {
return mediator;
}
public void register(Colleague colleague) {
if (!colleagues.contains(colleague)) {
colleagues.add(colleague);
}
}
public void send(Colleague colleague, String message) {
// 实现群发功能
for (Colleague user : colleagues) {
if (!user.equals(colleague)) {
// 模拟赵六不是任何人的朋友,即赵六接收不到任何人的消息
if (user.getUserName() != "赵六") {
user.receive(message);
}
}
}
}
}
抽象同事:
package mediator.simple;
public abstract class Colleague {
private String userName;
public Colleague(String userName) {
this.userName = userName;
Mediator.getMediator().register(this);
}
public String getUserName() {
return userName;
}
public abstract void receive(String message);
public abstract void send(String message);
}
具体同事:
package mediator.simple;
public class ConcreteColleague extends Colleague {
public ConcreteColleague(String userName) {
super(userName);
}
@Override
public void receive(String message) {
System.out.println(this.getUserName() + "收到了消息,消息内容是:" + message);
}
@Override
public void send(String message) {
System.out.println(this.getUserName() + "群发消息,消息内容是:" + message);
Mediator.getMediator().send(this, message);
}
}
Client:
package mediator.simple;
public class Client {
public static void main(String[] args) {
// 创建4个用户,其中3个用户直接是好友关系,而用户姓名为赵六的没有好友
Colleague user1 = new ConcreteColleague("赵日天");
Colleague user2 = new ConcreteColleague("张三");
Colleague user3 = new ConcreteColleague("李四");
Colleague user4 = new ConcreteColleague("王五");
// 模拟用户给好友群发消息
user2.send("新年快乐!");
System.out.println("============");
user3.send("祝大家新年快乐!");
/**
* 输出结果:
* 张三群发消息,消息内容是:新年快乐!
* 李四收到了消息,消息内容是:新年快乐!
* 王五收到了消息,消息内容是:新年快乐!
* ============
* 李四群发消息,消息内容是:祝大家新年快乐!
* 张三收到了消息,消息内容是:祝大家新年快乐!
* 王五收到了消息,消息内容是:祝大家新年快乐!
*/
}
}
三、总结
- 中介者模式也叫做调停者模式,一个对象要和N多个对象交流,就像对象间的战争,很混乱。这时,需要加入一个中心,所有的类都和中心交流,中心说怎么处理就怎么处理。
- 中介者模式是一个非常好的封装模式,但使用中介模式就必然会带来中介者的膨胀问题,这在一个项目中是很不恰当的。在N个对象之间产生了相互的依赖关系(N>2)可以考虑使用中介者模式。