设计模式之中介者模式
前言
我们现实生活中存在很多复杂的 网状结构 的交互关系,例如每个人必须记录他(她)所有朋友的手机号,
如果其中有人的手机号修改了,就必须通知他(她)所有的朋友一起修改,牵一发而动全身,非常复杂,
如果将这种 网状结构 变成 星状结构,将大大降低它们之间的耦合度,添加一个中介者,
在网上建立一个每个朋友都可以访问的通讯录,如QQ,我们修改了个人信息,其他人自然就看到了。
定义
用一个中介对象来封装一系列的对象交互,中介者使得各对象不需要显式的相互引用,从而使其耦合松散,而且可以独立的改变它们之间的交互。
结构
- Colleague,抽象同事类,每个同事类都知道中介者对象。
- ConcreteColleague,具体同事类,通过中介者来和其他的同事类交互。
- Mediator,中介者接口,定义各个同事之间需要交互的方法。
- ConcreteMediator,具体中介者,了解并维护各个同事对象,协调各同事之间的交互关系。
简单实现
抽象同事类
/**
* 抽象同事类
*/
public abstract class Colleague {
private Mediator mediator;
public Colleague(Mediator mediator) {
this.mediator = mediator;
}
public Mediator getMediator() {
return mediator;
}
}
具体同事类
/**
* 具体同事类A
*/
public class ConcreteColleagueA extends Colleague {
public ConcreteColleagueA(Mediator mediator) {
super(mediator);
}
public void someOperation() {
getMediator().changed(this);
}
}
另一个同事类
/**
* 具体同事类B
*/
public class ConcreteColleagueB extends Colleague {
public ConcreteColleagueB(Mediator mediator) {
super(mediator);
}
public void someOperation() {
System.out.println("ConcreteColleagueB.someOperation");
}
}
中介者接口
/**
* 中介者接口
*/
public interface Mediator {
void changed(Colleague colleague);
}
具体中介者
/**
* 具体中介者
*/
public class ConcreteMediator implements Mediator {
private ConcreteColleagueA concreteColleagueA;
private ConcreteColleagueB concreteColleagueB;
public void setConcreteColleagueA(
ConcreteColleagueA concreteColleagueA) {
this.concreteColleagueA = concreteColleagueA;
}
public void setConcreteColleagueB(
ConcreteColleagueB concreteColleagueB) {
this.concreteColleagueB = concreteColleagueB;
}
@Override
public void changed(Colleague colleague) {
if (colleague == concreteColleagueA) {
concreteColleagueB.someOperation();
}
}
}
客户端
public class Client {
public static void main(String[] args) {
//中介者
ConcreteMediator mediator = new ConcreteMediator();
//两个同事对象
ConcreteColleagueA colleagueA = new ConcreteColleagueA(mediator);
ConcreteColleagueB colleagueB = new ConcreteColleagueB(mediator);
mediator.setConcreteColleagueA(colleagueA);
mediator.setConcreteColleagueB(colleagueB);
//同事操作
colleagueA.someOperation();
}
}
在实际开发中,我们可以简化中介者模式,去除中介者接口,直接将中介者实现为一个单例,这样同事对象中就不需要持有中介者对象了。
同事类也不需要有一个共同的抽象父类,任意的对象都可以成为同事。这种实现可以看做广义的中介者模式。
/**
* 具体中介者,单例实现
*/
public class ConcreteMediator {
private static final ConcreteMediator INSTANCE = new ConcreteMediator();
private ConcreteMediator() {
}
public static ConcreteMediator getInstance() {
return INSTANCE;
}
public void colleagueBOperation() {
new ConcreteColleagueB().someOperation();
}
}
两个具体同事类
/**
* 具体同事类A
*/
public class ConcreteColleagueA {
public void someOperation() {
ConcreteMediator.getInstance().colleagueBOperation();
}
}
/**
* 具体同事类B
*/
public class ConcreteColleagueB {
public void someOperation() {
System.out.println("ConcreteColleagueB.someOperation");
}
}
客户端
public class Client {
public static void main(String[] args) {
new ConcreteColleagueA().someOperation();
}
}
中介者模式在SpringMVC的实现
SpringMVC中的DispatcherServlet
public class DispatcherServlet extends FrameworkServlet {
/** List of HandlerMappings used by this servlet. */
@Nullable
private List<HandlerMapping> handlerMappings;
/** List of HandlerAdapters used by this servlet. */
@Nullable
private List<HandlerAdapter> handlerAdapters;
/** List of HandlerExceptionResolvers used by this servlet. */
@Nullable
private List<HandlerExceptionResolver> handlerExceptionResolvers;
/** List of ViewResolvers used by this servlet. */
@Nullable
private List<ViewResolver> viewResolvers;
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
try {
try {
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
}
}
DispatcherServlet作为中介者协调具体http请求对象,Controller对象,视图View对象之间的交互。
总结
优点
- 将多个同事之间的交互封装到中介者对象中,同事对象之间低耦合。
- 多对多的关系变成了一对多,中介者集中控制同事之间的交互,当交互需要变化时,直接修改中介者。
缺点
- 过度集中化,中介者对象可能会变得非常复杂。
本质
中介者模式的本质是封装交互。只要是实现封装对象之间的交互功能,就可以应用中介者模式,标准的中介者模式限制很多,只要本质不变,就可以看做中介者模式。
使用场景
- 如果一组对象之间的交互关系比较复杂,相互依赖,结构混乱,这种情况下可以采用中介者模式。
参考
大战设计模式【21】—— 中介者模式
设计模式的征途—22.中介者(Mediator)模式
中介者模式(详解版)
设计模式(十九)——中介者模式(智能家庭案例)
Mediator Pattern
研磨设计模式-书籍