对于“中介”这个角色,大家在现实生活中也不陌生,比如房产中介。试想一下,如果没有中介这个角色,租房者和房东的关系直接的联系将呈现为网状结构,租房者和房东的关系将是多对多的关系,关系很复杂。当有房产中介的时候,租房者和房东之间将不用在一一的去交互,大家都只要和房产中介这一角色进行交互即可,由中介对象来管理对象的关联关系,避免相互交互的对象之间的紧耦合引用关系。这样,网状结构关系就简化为星型结构关系。如:
同样,在现实生活中的机场飞机起飞和降落,也都是和机场塔台交互,而不是飞机之间的进行交互的。如:
这种用一个中介对象(或者调停者)来封装一系列的对象交互的场景,就是今天要讲的中介者模式所使用的。
意图
用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
结构
中介者模式的基本结构如下:
这里涉及到的参与者有如下几种:
参与者如何协作?
同事向一个中介者对象发送和接收请求。中介者在各同事间适当地转发请求以实现写作行为。
接下来以一个模拟聊天室的简易代码来说明下中介者模式:
package com.wangmengjun.tutorial.designpattern.mediator;
public abstract class Participant {
protected String name;
public abstract void send(String message);
public abstract void receive(String message, String sender);
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
}
package com.wangmengjun.tutorial.designpattern.mediator;
public class User extends Participant {
private Mediator mediator = new ChatRoomMediator();
public User(String name, Mediator mediator) {
super();
this.name = name;
this.mediator = mediator;
mediator.addParticipant(this);
}
@Override
public void send(String message) {
System.out.println(String.format("[%s]发送一条消息 :[%s]", this.getName(),message));
mediator.sendMessage(message, this);
}
@Override
public void receive(String message, String sender) {
System.out.println(String.format("[%s]收到一条来自[%s]发送的消息 [%s]", this.getName(),sender,message));
}
}
package com.wangmengjun.tutorial.designpattern.mediator;
public interface Mediator {
void sendMessage(String message, Participant participant);
void addParticipant(Participant participant);
}
package com.wangmengjun.tutorial.designpattern.mediator;
import java.util.ArrayList;
import java.util.List;
public class ChatRoomMediator implements Mediator{
private List<Participant> participants = new ArrayList<Participant>();
@Override
public void sendMessage(String message, Participant participant) {
for(Participant p : participants){
if(p != participant){
p.receive(message,participant.getName() );
}
}
}
@Override
public void addParticipant(Participant participant) {
participants.add(participant);
}
}
测试一下:
package com.wangmengjun.tutorial.designpattern.mediator;
public class Main {
public static void main(String[] args) {
Mediator chatRoom = new ChatRoomMediator();
User eric = new User("Eric",chatRoom);
User lucy = new User("Lucy",chatRoom);
User lilei = new User("LiLei",chatRoom);
User xiaoming = new User("XiaoMing",chatRoom);
eric.send("周末一起聚聚啊~~~");
System.out.println();
xiaoming.send("好啊");
System.out.println();
lilei.send("可以啊");
System.out.println();
lucy.send("好啊好啊,啤酒烤串搞起来");
}
}
输出结果:
[Eric]发送一条消息 :[周末一起聚聚啊~~~]
[Lucy]收到一条来自[Eric]发送的消息 [周末一起聚聚啊~~~]
[LiLei]收到一条来自[Eric]发送的消息 [周末一起聚聚啊~~~]
[XiaoMing]收到一条来自[Eric]发送的消息 [周末一起聚聚啊~~~]
[XiaoMing]发送一条消息 :[好啊]
[Eric]收到一条来自[XiaoMing]发送的消息 [好啊]
[Lucy]收到一条来自[XiaoMing]发送的消息 [好啊]
[LiLei]收到一条来自[XiaoMing]发送的消息 [好啊]
[LiLei]发送一条消息 :[可以啊]
[Eric]收到一条来自[LiLei]发送的消息 [可以啊]
[Lucy]收到一条来自[LiLei]发送的消息 [可以啊]
[XiaoMing]收到一条来自[LiLei]发送的消息 [可以啊]
[Lucy]发送一条消息 :[好啊好啊,啤酒烤串搞起来]
[Eric]收到一条来自[Lucy]发送的消息 [好啊好啊,啤酒烤串搞起来]
[LiLei]收到一条来自[Lucy]发送的消息 [好啊好啊,啤酒烤串搞起来]
[XiaoMing]收到一条来自[Lucy]发送的消息 [好啊好啊,啤酒烤串搞起来]
中介者模式的优缺点:
优点:
(1):减少子类生成。Mediator将原本分布在多个对象间的行为集中在一起。改变这些行为只需生成Mediator的子类即可。这样各个Colleague类可被重用。
(2):它将各个Colleague解耦。Mediator有利于各Colleague间的松耦合,你可以独立的改变和复用各个Colleague类和Mediator类。
(3):中介者模式将多对多的相互作用转化为一对多的相互作用,使得对象之间的关系更加易于维护和理解。
(4):中介者模式将对象的行为和协作抽象化,将中介作为一个独立的概念并将其封装在一个对象中,使你的注意力从对象各自本身的行为转移到它们之间的交互上来。这有助于弄清楚一个系统中的对象是如何交互的。
缺点:
(1):调停者模式降低了同事对象的复杂性,代价是增加了中介者类的复杂性。这可能使得中介者自身成为一个难以维护的庞然大物。
(2):中介者经常充满了各个具体同事类的关系协调代码,这种代码常常是不能复用的。因此,具体同事类的复用是以中介者类的不可复用为代价的。
中介者模式 vs. 门面模式
门面模式和中介者模式很相似,两者均用来给出一个低耦合的系统。门面模式为一个子系统提供一个简单的接口,其中消息的传递是单方向的,因为门面模式的客户端只需要通过门面向子系统发出消息,而不是相反的情况。
中介者模式则不同,它与同事对象的相互作用是多方向的。
中介者模式 vs. 观察者模式
中介者(Mediator)强调的是同事(Colleague)类之间的交互而观察者(Observer)中的目标类(Subject)强调是目标改变后对观察者进行统一的通讯。
观察者模式需要观察者对象和主题对象的相互协作才能达到目的,而且一个观察主题对象通常有几个观察者对象,而一个观察者对象也可以同时观察几个主题对象。
Colleague可以使用观察者模式与Mediator进行交互。
参考
[1]. 阎宏. Java与模式.电子工业出版社
[2]. Erich Gamma. 设计模式-可复用面向对象软件的基础. 机械工业出版社.