概述
中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。中介者模式属于行为型模式。
意图:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
主要解决:对象与对象之间存在大量的关联关系,这样势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理。
何时使用:多个类相互耦合,形成了网状结构。
如何解决:将上述网状结构分离为星型结构。
关键代码:对象 Colleague 之间的通信封装到一个类中单独处理。
应用实例:如婚介所、房产中介、交换机组网、现代电子商务、C2C购物平台、手机、即时通软件等等,这些都与我们的生活息息相关,离开它们我们将举步维艰。其实不管是任何中介,其本质都是相同的,都是充当中间媒介的角色,并达成多方业务互通的目的
优点:
1、降低了对象之间的耦合性,使得对象易于独立地被复用。
2、将对象间的一对多关联转变为一对一的关联,提高系统的灵活性,使得系统易于维护和扩展。
缺点:
中介者模式将原本多个对象直接的相互依赖变成了中介者和多个同事类的依赖关系。当同事类越多时,中介者就会越臃肿,变得复杂且难以维护。
中介者模式的结构
抽象中介者(Mediator)角色:它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法。
具体中介者(Concrete Mediator)角色:实现中介者接口,定义一个 List 来管理同事对象,协调各个同事角色之间的交互关系,因此它依赖于同事角色。
抽象同事类(Colleague)角色:定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。
具体同事类(Concrete Colleague)角色:是抽象同事类的实现者,当需要与其他同事对象交互时,由中介者对象负责后续的交互。
中介者模式的使用
我们首先以两个人聊天为例,这里是没有中介的。
public class People {
private String name;
private People other;//持有对方的引用
public String getName()
{
return this.name;
}
public People(String name)
{
this.name = name;
}
public void connect(People other)
{
this.other = other;//用于连接说话的人
}
public void talk(String msg)
{
other.listen(msg);//听者调用听的方法
}
public void listen(String msg)
{
//这里的this为听者,other为说者
System.out.println(other.getName()+"对"+this.name+"说:"+msg);
}
}
main方法运行结果如下:
public class Main {
public static void main(String[] args) {
People p1 = new People("张三");
People p2 = new People("李四");
//互相建立连接
p1.connect(p2);
p2.connect(p1);
p1.talk("你好");
p2.talk("早上好,小张");
}
}
从People类中我们可以看到,沟通只只能在两人之间进行,而且各自都持有对方对象的引用,以便把消息传递给对方的监听方法。这种模式虽然简单,但耦合性太强,你中有我,我中有你,谁也离不开谁。试想如果再有多个人加入交谈,那每个人都要持有其他所有人的引用了,这时会陷入一种多对多的关联陷阱,对象关系变得复杂不堪,如蛛网般难以维护。
这时候我们就需要一个中介者来将这么多对象的网状结构给抽离出来,把对方的引用放在一个中介类里面去统一维护起来,于是设计更改如下。
我们这里拿聊天室来举例,让每个用户不再所持有其他所有用户的引用了,取而代之的是聊天室的引用,这样引用关系瞬间变得明朗起来。
重构一下人员类:
public class User {
private String name;
private ChatRoom chatRoom;//所属聊天室
public String getName() {
return this.name;
}
public User(String name) {
this.name = name;
}
public void login(ChatRoom chatRoom) {
chatRoom.connect(this);
this.chatRoom = chatRoom;
}
public void talk(String msg) {
chatRoom.sendMsg(this, msg);
}
public void listen(User userFrom, String msg) {
System.out.println("【" + this.name + "的对话框】 " + userFrom.name + " 说:" + msg);
}
}
再加入聊天室作为我们的中介者,负责多个用户之间的消息处理。
public class ChatRoom {
private String name;//聊天室的名称
public ChatRoom(String name) {
this.name = name;
}
List<User> users = new ArrayList<>(); //聊天室的用户群
public void connect(User user) {
this.users.add(user);
System.out.println("欢迎【" + user.getName() + "】加入聊天室");
}
public void sendMsg(User userFrom, String msg) {
//发送消息给所有非发送方
users.stream().filter(user -> !user.equals(userFrom)).forEach(user -> {
user.listen(userFrom, msg);
});
}
}
main方法如下:
public class Main {
public static void main(String[] args) {
User user1 = new User("张三");
User user2 = new User("李四");
User user3 = new User("王五");
User user4 = new User("赵六");
ChatRoom chatRoom = new ChatRoom("聊天室1");
user1.login(chatRoom);
user2.login(chatRoom);
user3.login(chatRoom);
user4.login(chatRoom);
user1.talk("来来来上号打王者了!!!!");
}
}
运行结果如下:
这里我们只用了具体中介者角色和具体同事类角色,当我们要扩展此程序衍生出更多的交互时,我们只需要抽取对应(具体同事类和具体中介者类)的抽象类就好了,但是注意在同事类增多时控制具体中介者类的业务逻辑别耦合太多变得臃肿。