设计模式之中介者模式

前言

我们现实生活中存在很多复杂的 网状结构 的交互关系,例如每个人必须记录他(她)所有朋友的手机号,
如果其中有人的手机号修改了,就必须通知他(她)所有的朋友一起修改,牵一发而动全身,非常复杂,
如果将这种 网状结构 变成 星状结构,将大大降低它们之间的耦合度,添加一个中介者,
在网上建立一个每个朋友都可以访问的通讯录,如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对象之间的交互。

总结

优点

  1. 将多个同事之间的交互封装到中介者对象中,同事对象之间低耦合。
  2. 多对多的关系变成了一对多,中介者集中控制同事之间的交互,当交互需要变化时,直接修改中介者。

缺点

  1. 过度集中化,中介者对象可能会变得非常复杂。

本质

中介者模式的本质是封装交互。只要是实现封装对象之间的交互功能,就可以应用中介者模式,标准的中介者模式限制很多,只要本质不变,就可以看做中介者模式。

使用场景

  1. 如果一组对象之间的交互关系比较复杂,相互依赖,结构混乱,这种情况下可以采用中介者模式。

参考

大战设计模式【21】—— 中介者模式
设计模式的征途—22.中介者(Mediator)模式
中介者模式(详解版)
设计模式(十九)——中介者模式(智能家庭案例)
Mediator Pattern
研磨设计模式-书籍

posted @ 2021-08-16 20:28  strongmore  阅读(84)  评论(0编辑  收藏  举报