Java 23 种设计模式:从踩坑到精通 | 番外:外观 vs 中介者 —— DispatcherServlet 为什么是两个模式的合体?

摘要:外观模式和中介者模式都充当“中间人”角色,但外观是单向调用的“统一入口”,中介者是双向协调的“通信枢纽”。Spring MVC 的 DispatcherServlet 是理解这两个模式的绝佳案例——它对外为所有 Controller 提供统一入口(外观模式),对内协调 HandlerMappingHandlerAdapterViewResolver 等组件之间的交互(中介者模式)。本文从 DispatcherServlet 源码出发,结合 UML 对比、代码实现和面试高频题,帮你彻底分清这对“结构型 vs 行为型”的中间人组合。

🗺️ 本文阅读地图(3 分钟速览)

  • 为什么 DispatcherServlet 同时扮演“入口”和“枢纽”?
  • 外观 vs 中介者:一张表看懂单向简化 vs 双向协调
  • UML 对比:星型结构 vs 网状扁平化
  • Spring MVC 源码级分析:doDispatch() 如何体现两种模式
  • 面试必问:“外观和中介者有什么区别?DispatcherServlet 用了哪个?”

📖 《Java 23 种设计模式:从踩坑到精通》
开篇:系列介绍与目录 | 当前:番外 · 外观 vs 中介者
🔗 返回系列总目录



1. 从一个“请求处理”的流程说起

在 Spring MVC 中,一个 HTTP 请求的处理流程大概是这样的:

  1. 浏览器发送 /order/query 请求;
  2. DispatcherServlet 接收请求,分发给对应的 Controller;
  3. Controller 返回 ModelAndView,由 ViewResolver 解析视图;
  4. 最终渲染 HTML 返回给浏览器。

在这个过程中,DispatcherServlet 扮演了两个截然不同的角色:

  • 对客户端(浏览器)来说,它就是一个统一的“入口”——无论什么请求,客户端只与 DispatcherServlet 交互,完全不知道背后有 HandlerMappingHandlerAdapterViewResolver 等一堆组件。这体现的是外观模式

  • 对内部组件来说,它是一个“协调中心”——HandlerMapping 找到处理器后不直接调用 Controller,而是把结果交给 DispatcherServletHandlerAdapter 执行完也不直接返回视图,而是把 ModelAndView 交还给 DispatcherServlet。所有组件之间的交互都通过 DispatcherServlet 中转。这体现的是中介者模式

// DispatcherServlet 核心方法(简化版)
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) {
    // 1. 外观模式:对外统一入口——无论什么请求,都走这个方法
    HttpServletRequest processedRequest = checkMultipart(request);
    
    // 2. 中介者模式:内部组件通过 DispatcherServlet 协调
    Object handler = getHandler(processedRequest);       // HandlerMapping → 中介者
    HandlerAdapter ha = getHandlerAdapter(handler);      // 中介者 → HandlerAdapter
    ModelAndView mv = ha.handle(processedRequest, response, handler); // HandlerAdapter → 中介者
    processDispatchResult(processedRequest, response, mappedHandler, mv); // 中介者 → ViewResolver
}

2. UML 对比:星型结构 vs 网状扁平化

2.1 外观模式 UML(星型结构)

在这里插入图片描述

2.2 中介者模式 UML(网状扁平化)

在这里插入图片描述


3. 四大核心区别

对比维度 外观模式 中介者模式
意图 提供统一的单向调用入口,简化客户端使用 封装对象之间的双向交互,降低耦合
通信方向 单向:外观 → 子系统 双向:同事 ↔ 中介者 ↔ 同事
子系统感知 子系统不知道外观的存在 同事类知道中介者的存在,并通过它通信
典型应用 SLF4J、JdbcTemplate、微服务网关 Spring MVC DispatcherServlet(对内)、聊天室、消息中间件

💡 简单记忆:外观是“一键启动按钮”(单向),中介者是“中央调度台”(双向)。你按下观影按钮,外观替你操作所有设备,设备不知道外观的存在;你在聊天室发消息,中介者把消息转发给所有人,每个人都知道中介者的存在。


4. DispatcherServlet 源码分析:两个模式的完美合体

4.1 外观模式体现:统一的请求入口

无论什么请求(GET、POST、JSON、文件上传),对于客户端来说,只有一个入口——DispatcherServlet

// DispatcherServlet 对外:统一的入口方法
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 所有请求都走这个方法,客户端无需关心内部细节
    doDispatch(request, response);
}

外观特征

  • 客户端(浏览器)只知道 DispatcherServlet 这一个入口;
  • 客户端完全不知道 HandlerMappingHandlerAdapterViewResolver 的存在;
  • 如果内部组件升级(比如换一个 ViewResolver 实现),客户端代码零修改。

4.2 中介者模式体现:内部组件的协调中心

// DispatcherServlet 对内:各个组件通过 DispatcherServlet 协调
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) {
    // 1. HandlerMapping 找到处理器 → 返回给中介者
    Object handler = getHandler(request);  
    
    // 2. 中介者根据 handler 类型找到对应的 HandlerAdapter
    HandlerAdapter ha = getHandlerAdapter(handler);  
    
    // 3. HandlerAdapter 执行处理器 → 返回 ModelAndView 给中介者
    ModelAndView mv = ha.handle(request, response, handler);  
    
    // 4. 中介者调用 ViewResolver 解析视图
    processDispatchResult(request, response, mappedHandler, mv);
}

中介者特征

  • HandlerMapping 不直接调用 Controller,而是把结果返回给 DispatcherServlet
  • HandlerAdapter 不直接返回视图,而是把 ModelAndView 交还给 DispatcherServlet
  • ViewResolverDispatcherServlet 接收数据,而不是从 Controller 直接获取;
  • 所有组件之间不直接交互,全部通过 DispatcherServlet 中转。

4.3 一张图看懂合体设计

在这里插入图片描述

💡 一句话总结DispatcherServlet 对外是外观(客户端只看得到它一个入口),对内是中介者(所有组件通过它协调交互)。两者互不冲突,各司其职。


5. 面试必问 + 追问连环炮

基础必问

  • 外观模式和中介者模式有什么区别?
    👉 外观是单向调用简化入口,子系统不知道外观存在;中介者是双向协调交互,同事类知道中介者并依赖它。
  • Spring MVC 的 DispatcherServlet 用了什么模式?
    👉 对外体现外观模式(统一入口),对内体现中介者模式(协调 HandlerMapping、HandlerAdapter、ViewResolver 等组件)。
  • SLF4J 用了什么设计模式?
    👉 外观模式。它提供统一日志接口,后端绑定 Logback、Log4j2 等实现。

面试官追问

  • DispatcherServlet 为什么需要同时用两种模式?”
    👉 对外简化客户端调用(外观),对内解耦组件交互(中介者)。如果只用外观,内部组件之间会产生网状依赖;如果只用中介者,客户端需要知道内部组件的存在。两者配合才能同时解决“对外简洁”和“对内解耦”两个问题。
  • “你能再举一个同时用到外观和中介者的例子吗?”
    👉 微服务架构中的 API 网关。网关对外是外观——客户端只与网关交互,不知道后端服务的细节;网关对内是中介者——它协调服务发现、负载均衡、认证鉴权等组件的交互。
  • “消息队列(RabbitMQ/Kafka)的 Broker 是什么模式?”
    👉 中介者模式。生产者不直接发给消费者,而是通过 Broker 中转,Broker 负责路由、广播、持久化。

🎉 恭喜:如果你能立刻说出 DispatcherServlet 对外是外观、对内是中介者,并理解两者的单向/双向区别,你已经掌握了“中间人”模式最核心的辨析点。

💡 延伸阅读:本文是外观模式与中介者模式的深度对比。如果你想先了解每种模式的完整原理、UML、代码实现和面试题,可以先阅读正篇——外观模式:给复杂系统装一个“一键启动”中介者模式:对象关系太乱?请一位“中间人”,再回来看这篇对比,效果更佳。


🧭 《Java 23 种设计模式:从踩坑到精通》快速导航

🔔 关注《Java 23 种设计模式:从踩坑到精通》,用 25 篇文章彻底吃透设计模式。
📦 福利预告:全系列代码及 UML 源码将在完结时统一打包开放,点击「关注」「收藏」第一时间获取。

📌 除了设计模式,我也在深挖智能物流实战(WMS、托盘调度、机器学习落地)。欢迎点击头像,看看专栏 《出版社物流WMS智能调度实战》。技术相通,思路可鉴。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐