中介者模式听名字就能想到也是一种为了解决耦合度的设计模式,其实中介者模式在结构上与观察者、命令模式十分相像;而应用目的又与结构模式“门面模式”有些相似。但区别于命令模式的是大多数中介者角色对于客户程序是透明的。当然造成这种区别的原因是由于他们要达到的目的不同。
中介者模式是指用一个中介对象来封装一系列的对象交互。中介者使个对象不需要显示的相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。简单地说,将原来两个直接引用或者依赖的对象拆开,在中间加入一个“中介”对象,使得两头的对象分别与“中介”对象引用或者依赖。
例如下面这个结构,如果每个元素两两之间要产生联系,关系就会变得错综复杂。
但是加了中介者之后,相互之间就可以解耦了。变成如下的关系结构。
和二跟老纪都是朝廷大臣,但是互相看不顺眼,在皇上面前和和气气,背地里各自互相参对方。当然有时候皇上颁布旨意时让两个大臣一起合作去完成任务,他们也会相互合作的。和二跟老纪都想收拾对方,但是奈何双方官职不相上下,所以当想收拾对方时就会通过皇上来实现,这个时候我们就当皇上理解为中介者(感觉有点牵强,就这样吧?)。下面用代码来实现这个过程。
官员抽象类
/**
* 官员(大臣)抽象类
*/
public abstract class Official {
protected Monarch monarch;
/**
* 每个官员必然要与君主有联系
* @param monarch
*/
public Official(Monarch monarch){
this.monarch = monarch;
}
/**
* 在抽象官员类中添加与中介者取得联系的方法
* @param monarch
*/
public void setMonarch(Monarch monarch){
this.monarch = monarch;
}
}
君主抽象类
/**
* 君主抽象类
*/
public abstract class Monarch {
/**
* 君主保持着和各个官员的联系
*/
protected ConcurrentHashMap<String,Official> officials = new ConcurrentHashMap<>();
/**
* 录用官员
* @param name
* @param official
*/
public void addOfficial(String name,Official official){
this.officials.put(name,official);
}
/**
* 将官员革职查办
* @param name
*/
public void removeOfficial(String name){
this.officials.remove(name);
}
/**
* 处理各个官员之间的互相参奏的折子
* @param name
* @param method
*/
public abstract void execute(String name,String method);
}
老纪
/**
* 老纪
*/
public class LaoJi extends Official{
/**
* 每个官员必然要与君主有联系
*
* @param monarch
*/
public LaoJi(Monarch monarch) {
super(monarch);
}
/**
* 做好本职工作
*/
public void self(){
System.out.println("启奏皇上,臣老纪参与编写的四库全书已经完成。");
}
/**
* 参其他官员或与其他官员合作
*/
public void out(){
System.out.println("启奏皇上,臣老纪要参和二一本,秀女选拔工作到现在还没完成,理应当革职查办。");
super.monarch.execute("heEr","self");
}
}
和二
/**
* 和二
*/
public class HeEr extends Official {
/**
* 每个官员必然要与君主有联系
*
* @param monarch
*/
public HeEr(Monarch monarch) {
super(monarch);
}
/**
* 做好本职工作
*/
public void self(){
System.out.println("启奏皇上,臣和二掌管的秀女选拔工作已经完成。");
}
/**
* 参其他官员或与其他官员合作
*/
public void out(){
System.out.println("启奏皇上,臣和二要参老纪一本,四库全书到目前还没编写完成,理应问斩。");
super.monarch.execute("laoji","self");
}
}
黄三(乾隆皇上)
/**
* 黄三(皇上)
*/
public class HuangSan extends Monarch {
/**
* 处理各个官员之间的互相参奏的折子
*
* @param name
* @param method
*/
@Override
public void execute(String name, String method) {
//做好自己份内的事情
if("self".equals(method)){
if("laoji".equals(name)){
((LaoJi)super.officials.get(name)).self();
}else {
((HeEr)super.officials.get(name)).self();
}
//我要参别人一本
}else {
if("laoji".equals(name)){
((LaoJi)super.officials.get(name)).out();
}else {
((LaoJi)super.officials.get(name)).out();
}
}
}
}
测试类
public class Client {
public static void main(String[] args) {
//创建一个君主
Monarch monarch = new HuangSan();
//创建两个官员
LaoJi laoJi = new LaoJi(monarch);
HeEr heEr = new HeEr(monarch);
//君主和两个官员建立关系
monarch.addOfficial("laoji",laoJi);
monarch.addOfficial("heEr",heEr);
//有本奏上,无本退朝。
//laoJi.self();
laoJi.out();
System.out.println("---------------启奏完毕");
//heEr.self();
heEr.out();
System.out.println("---------------启奏完毕");
}
}
运行结果
启奏皇上,臣老纪要参和二一本,秀女选拔工作到现在还没完成,理应当革职查办。
启奏皇上,臣和二掌管的秀女选拔工作已经完成。
---------------启奏完毕
启奏皇上,臣和二要参老纪一本,四库全书到目前还没编写完成,理应问斩。
启奏皇上,臣老纪参与编写的四库全书已经完成。
---------------启奏完毕
上面的这个例子就是实现了中介者模式,皇上成了老纪跟和二的中介者。这样使得两位大臣也不用直接互怼了,除了干好自己的本职工作还可以督促其他同事完成工作。
中介者模式的组成角色如下所示
抽象中介者(Mediator)角色:抽象中介者角色定义统一的接口,用于各同事角色之间的通信。上面例子中君主类代表的就是这个角色。
具体中介者(ConcreteMediator)角色:具体中介者角色通过协调各同事角色,实现协作行为,为此它要指导并引用各个同事角色。上面例子中皇上代表的就是这个角色。
同事(Colleague)角色:每一个同事角色都知道对应的具体中介者角色,而且与其他的同事角色通信的时候,一定要通过中介者角色协作。上面的例子中老纪跟和二就是代表的这个角色。
中介者模式将一个网状的系统结构变成一个以中介者对象为中心的星形结构,在这个星型结构中,使用中介者对象与其他对象的一对多关系来取代原有对象之间的多对多关系。
1、中介者模式简化了对象之间的交互,它用中介者和同事的一对多交互代替了原来同事之间的多对多交互,一对多关系更容易理解、维护扩展,将原本难以理解的网状结构转换成相对简单的星型结构。
2、中介者模式可将各同事对象解耦。中介者有利于各同事之间的松耦合,我们可以独立的改变和复用每一个同事和中介者,增加新的中介者和新的同事类都比较方便,更好的符合“开闭原则”。
3、可以减少子类生成,中介者将原本分布于多个对象间的行为集中在一起,改变这些行为只需生成新的中介者子类即可,这使得各个同事类可被重用,无须对同事类进行扩展。
在具体中介者类中包含了大量同事之间的交互细节,可能会导致具体中介者类非常复杂,使得系统难以维护。
1、系统中对象之间存在复杂的引用关系,系统结构混乱且难以理解。
2、 一个对象由于引用了其他很多对象并且直接和这些对象通信,导致难以复用该对象。
3、想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。可以通过引入中介者类来实现,在中介者中定义对象交互的公共行为,如果需要改变行为则可以增加新的具体中介者类。
想了解更多的设计模式请查看Java设计模式学习记录-GoF设计模式概述。