1. 什么是中介者模式?
中介者模式(Mediator Pattern)是用一个中介对象(中介者)来封装一系列对象之间的交互,中介者使各对象之间不用显式的相互引用,从而使其耦合松散,而且可以独立的改变他们之间的交互。中介者模式又称为调停者模式,是一种对象行为型模式。
如果系统之中出现大量对象之间相互引用,将会造成
(1)系统结构变得复杂。对象与对象之间存在大量相互引用,若一个对象改变,与之关联的对象都可能要做出相应的改变。
(2)系统可扩展性降低。增加一个对象,就要去其他相关对象上面增加此对象的引用。增加了对象之间的耦合性。
(3)对象复用性降低。一个对象存在很多其他对象的引用,导致此对象不易于复用于其他场景。
图片源于网络
图中A对象中就有BCDHG对象的引用,A对象和这几个对象是直接耦合的,不易于扩展与维护。采用中介者模式后,所有对象都只和中介者(Mediator)打交道,所有的调用关系都是中介者来维护的。此时此刻A对象解脱了,假如A有份报告要交给BCD,他不用自己亲自给每个对象送去了,只需要交给Mediator转发给BCD就可以了。
但是一定要注意,因为中介者中维护了几乎所有对象的引用和调用行为,中介者会变得异常复杂和庞大。所以遇到大量对象相互引用的时候一定要权衡利弊,设计是否合理,不是说只要使用模式一定就是最好的。
2. 角色
图片源于网络
抽象中介者(Mediator):中介者抽象类。提供了一个同事对象联络的抽象方法。可以是接口或抽象类。
具体中介者(ConcreteMediator):实现抽象中介者类的抽象方法。具体中介者需要知道所有具体同事类,并且将一个具体同事类的信息传递给另一个具体同事类。
抽象同事(Colleague):定义所有具体同事的共同方法。可以是接口或抽象类。
具体同事(ConcreteColleague):实现抽象同事类的抽象方法。内部有一个中介者的引用。
3. 优点
(1)将系统对象与对象直接的调用关系分离出来进行单独封装,同事对象(Colleague)内没有显式的的调用其他同事对象,使耦合松散。
(2)同事对象(Colleague)抽离了对其他对象的引用,使得同事对象可以重用于不同的场景,不用单独扩展,可以使同事对象的数量减少。
4. 缺点
当使用中介者模式将对象与对象之间的调用关系分离出来后,中介者内部必须要知道每一个对象类和他们之间的调用关系,这会造成中介者代码复杂且庞大,很不容易维护。
如果有4个同事对象需要相互联系,则中介者对象中就会存在4*3=12种不同的相互调用方法,同事对象越多,中介者越复杂庞大。因此个人觉得,如果将接收者和发送者交给客户端来注册,不完全交给中间者管理,中介者对象只需要维护已经注册了的发送者和接收者,以及他们之间相互调用的公共方法,中介者会相对较好维护。如6例。
5. 使用场景
(1)系统对象之间存在复杂的引用关系,系统结构混乱难以理解。
(2)一个对象直接引用了其他对象,且直接和他们进行通信,造成这个对象难以复用与其他场景。
(3)想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。可以通过引入中介者类来实现,在中介者中定义对象交互的公共行为,如果需要改变行为则可以增加新的具体中介者类。
个人理解:其实这个就是造成中介者代码复杂庞大的原因,因为为了不生成太多的子类,中介者就需要维护所有的交互行为,4个对象就有12种交互行为,6个对象就有30种交互行为,因此示例代码中所举例子,采用一种折中的办法,中介者不维护所有的交互关系和交互对象,只维护抽象发送者、抽象接收者和公共调用关系,而实际的发送者和接收者交给客户端进行注册。
6. 示例代码
每种事物都具有两面性,此例子虽然解决了中介者类复杂庞大不好维护的缺点,但是却不能实现接收者与接收者对话,如B、C、D之间的对话。想要B、C、D之间相互对话必须重新注册接收者和发送者。
(1)抽象中介者
/**
* 抽象中介者类
*/
public interface IMediator {
/**
* 中介者给同事双方相互联系的方法
* @param person 发送请求的同事类
* @param message 发送的消息
*/
public void contact(String message,AbstractPerson person);
}
(2)具体中介者
/**
* 具体的中介者对象
*/
public class ConcreteMediator implements IMediator {
// 接收者(list列表可以实现一个发送者和多个接收者对话,一对多关系)
private List<AbstractPerson> receivers = new ArrayList<AbstractPerson>();
// 发送者
private AbstractPerson sender;
/**
* 注册接收者
* @param persons
*/
public void setReceiver(AbstractPerson... persons) {
if (persons != null && persons.length > 0)
for (AbstractPerson person : persons) {
receivers.add(person);
}
}
/**
* 删除接收者
* @param receiver
*/
public void removeReceiver(AbstractPerson...RECEIVERS) {
if (RECEIVERS != null && RECEIVERS.length > 0)
for(AbstractPerson receiver:RECEIVERS)
receivers.remove(receiver);
}
/**
* 注册发送者
* @param persen
*/
public void setSender(AbstractPerson persen) {
this.sender = persen;
}
@Override
public void contact(String message, AbstractPerson person) {
if (person == sender) {
for (AbstractPerson receiver : receivers)
receiver.handleMessage(message);
} else {
sender.handleMessage(message);
}
}
}
(3)抽象同事
/**
*公共抽象同事类
*由于有重复的属性和方法,此处采用abstract类
*/
public abstract class AbstractPerson {
protected IMediator mediator;
protected String personName;
public AbstractPerson(String personName,IMediator mediator) {
this.personName=personName;
this.mediator=mediator;
}
/**
* 同事之间联系的方法
* @param message 发送的消息
*/
public void contact(String message){
if(message!=null && !"".equals(message))
mediator.contact(message,this);
}
/**
* 此对象处理消息的方法
* @param message 接收到的消息
*/
public abstract void handleMessage(String message);
}
(4)具体同事
/**
* 具体同事A
*/
public class PersonA extends AbstractPerson {
public PersonA(String personName,IMediator mediator) {
super(personName, mediator);
}
@Override
public void handleMessage(String message) {
if(message!=null && !"".equals(message))
System.out.println(personName+" 收到消息:"+message);
}
}
/**
* 具体同事B
*/
public class PersonB extends AbstractPerson{
public PersonB(String personName,IMediator mediator) {
super(personName, mediator);
}
@Override
public void handleMessage(String message) {
if(message!=null && !"".equals(message))
System.out.println(personName+" 收到消息:"+message);
}
}
/**
* 具体同事C
*/
public class PersonC extends AbstractPerson {
public PersonC(String personName,IMediator mediator) {
super(personName, mediator);
}
@Override
public void handleMessage(String message) {
if(message!=null && !"".equals(message))
System.out.println(personName+" 收到消息:"+message);
}
}
/**
* 具体同事D
*/
public class PersonD extends AbstractPerson {
public PersonD(String personName,IMediator mediator) {
super(personName, mediator);
}
@Override
public void handleMessage(String message) {
if(message!=null && !"".equals(message))
System.out.println(personName+" 收到消息:"+message);
}
}
(5)测试
public class Client {
public static void main(String[] args) {
//new一个中介者
ConcreteMediator mediator=new ConcreteMediator();
//new一个发送者A
AbstractPerson personA=new PersonA("A君", mediator);
//new一个接收者B
AbstractPerson personB=new PersonB("B君", mediator);
//注册发送者
mediator.setSender(personA);
//注册接收者
mediator.setReceiver(personB);
System.out.println("A对B说:");
personA.contact("B君,你吃早饭没有?");
System.out.println("-----------");
//再new 多个接收者
AbstractPerson personC=new PersonC("C君", mediator);
AbstractPerson personD=new PersonD("D君", mediator);
mediator.setReceiver(personC,personD);
System.out.println("A对BCD说:");
personA.contact("你们今天编程了吗?");
System.out.println("-----------");
System.out.println("DBC分别回答A:");
personD.contact("A君,别装逼!");
personB.contact("呵呵");
personC.contact("今天天气不错!");
System.out.println("-----------");
//清除B和C接收者
mediator.removeReceiver(personB,personC);
System.out.println("A单独对D说:");
personA.contact("D君,别BB!");
}
}
(6)测试结果
A对B说:
B君 收到消息:B君,你吃早饭没有?
-----------
A对BCD说:
B君 收到消息:你们今天编程了吗?
C君 收到消息:你们今天编程了吗?
D君 收到消息:你们今天编程了吗?
-----------
DBC分别回答A:
A君 收到消息:A君,别装逼!
A君 收到消息:呵呵
A君 收到消息:今天天气不错!
-----------
A单独对D说:
D君 收到消息:D君,别BB!
注意:文中自我理解部分属于自己的对中介者模式的一种理解,不能说全对,若不对请批评指正!
【四川乐山程序员联盟,欢迎大家加群相互交流学习5 7 1 8 1 4 7 4 3】
参考文章http://www.cnblogs.com/chenssy/p/3348520.html