中介者模式:设计与实践
一、什么是中介者模式
1. 基本定义
中介者模式(Mediator Pattern)是一种行为型设计模式,由《设计模式:可复用面向对象软件的基础》(GOF著作)定义为:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
该模式通过引入一个中介者对象,将多个对象(同事类)之间的交互集中管理,同事类之间不再直接通信,而是通过中介者传递信息。核心是将“多对多”的复杂交互关系转化为“一对多”的简单关系,降低系统耦合度。
2. 核心思想
中介者模式的核心在于集中协调与解耦交互。当系统中存在多个对象需要相互通信时,对象间的直接引用会形成复杂的网状结构,导致系统难以维护和扩展。通过引入中介者,所有对象的交互都由中介者统一处理,对象只需关注自身业务逻辑,无需关心其他对象的存在,从而实现对象间的解耦,提高系统的灵活性和可维护性。
二、中介者模式的特点
1. 集中交互逻辑
所有对象间的交互逻辑被集中在中介者中,避免分散在各个对象中,便于统一管理和修改。
2. 减少直接依赖
同事类之间不直接引用,仅通过中介者通信,降低对象间的耦合度,形成“星形”依赖结构。
3. 简化对象职责
同事类只需关注自身业务逻辑,无需处理与其他对象的交互,职责更单一。
4. 易于扩展
新增交互规则只需修改中介者,新增同事类只需在中介者中添加相应处理逻辑,符合开闭原则。
5. 可能导致中介者膨胀
若系统中对象过多或交互复杂,中介者可能会变得庞大,承担过多职责,需要注意拆分。
| 特点 | 说明 |
|---|---|
| 集中交互逻辑 | 交互规则集中在中介者,避免分散 |
| 减少直接依赖 | 同事类通过中介者通信,无直接引用 |
| 简化对象职责 | 同事类专注自身业务,不处理交互 |
| 易于扩展 | 新增规则或对象只需修改中介者 |
| 可能导致中介者膨胀 | 复杂场景下中介者可能过于庞大 |
三、中介者模式的标准代码实现
1. 模式结构
中介者模式包含四个核心角色:
- 抽象中介者(Mediator):定义中介者与同事类交互的接口,声明协调同事类的方法。
- 具体中介者(ConcreteMediator):实现抽象中介者接口,持有所有同事类的引用,负责协调同事类的交互。
- 抽象同事类(Colleague):定义同事类的接口,持有抽象中介者的引用,提供与中介者通信的方法。
- 具体同事类(ConcreteColleague):实现抽象同事类接口,完成自身业务逻辑,通过中介者与其他同事类交互。
2. 代码实现示例
2.1 抽象中介者与同事类
/**
* 抽象中介者
*/
public interface Mediator {
/**
* 注册同事类
*/
void register(Colleague colleague);
/**
* 转发消息
*/
void relay(Colleague sender, String message);
}
/**
* 抽象同事类
*/
public abstract class Colleague {
protected Mediator mediator;
public Colleague(Mediator mediator) {
this.mediator = mediator;
}
/**
* 发送消息
*/
public abstract void send(String message);
/**
* 接收消息
*/
public abstract void receive(String message);
}
2.2 具体中介者与同事类
import java.util.ArrayList;
import java.util.List;
/**
* 具体中介者
*/
public class ConcreteMediator implements Mediator {
private List<Colleague> colleagues = new ArrayList<>();
@Override
public void register(Colleague colleague) {
colleagues.add(colleague);
}
@Override
public void relay(Colleague sender, String message) {
// 转发消息给除发送者外的其他同事
for (Colleague colleague : colleagues) {
if (colleague != sender) {
colleague.receive(message);
}
}
}
}
/**
* 具体同事类A
*/
public class ConcreteColleagueA extends Colleague {
public ConcreteColleagueA(Mediator mediator) {
super(mediator);
}
@Override
public void send(String message) {
System.out.println("同事A发送消息:" + message);
mediator.relay(this, message);
}
@Override
public void receive(String message) {
System.out.println("同事A收到消息:" + message);
}
}
/**
* 具体同事类B
*/
public class ConcreteColleagueB extends Colleague {
public ConcreteColleagueB(Mediator mediator) {
super(mediator);
}
@Override
public void send(String message) {
System.out.println("同事B发送消息:" + message);
mediator.relay(this, message);
}
@Override
public void receive(String message) {
System.out.println("同事B收到消息:" + message);
}
}
2.3 客户端使用示例
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
// 创建中介者
Mediator mediator = new ConcreteMediator();
// 创建同事类并注册到中介者
Colleague colleagueA = new ConcreteColleagueA(mediator);
Colleague colleagueB = new ConcreteColleagueB(mediator);
mediator.register(colleagueA);
mediator.register(colleagueB);
// 同事类通过中介者通信
System.out.println("=== 同事A发送消息 ===");
colleagueA.send("请确认当前状态");
System.out.println("\n=== 同事B发送消息 ===");
colleagueB.send("状态正常,可以执行操作");
}
}
3. 代码实现特点总结
| 角色 | 核心职责 | 代码特点 |
|---|---|---|
| 抽象中介者(Mediator) | 定义中介者与同事类的交互接口 | 声明register()(注册同事)和relay()(转发消息)等方法 |
| 具体中介者(ConcreteMediator) | 实现中介逻辑,协调同事类交互 | 持有同事类集合,relay()方法中实现消息转发或交互规则 |
| 抽象同事类(Colleague) | 定义同事类接口,持有中介者引用 | 包含mediator字段,声明send()和receive()方法 |
| 具体同事类(ConcreteColleague) | 实现自身业务,通过中介者交互 | 实现send()(调用中介者转发)和receive()(处理收到的消息)方法 |
四、支付框架设计中中介者模式的运用
以支付场景化营销协同场景为例,说明中介者模式在支付系统中的具体应用:
1. 场景分析
支付过程中,用户可能享受多种营销优惠(如优惠券、积分抵扣、银行补贴、满减活动),涉及多个营销组件的协同:
- 优惠券服务:验证并扣减可用优惠券
- 积分服务:查询用户积分并抵扣金额
- 银行活动服务:检查是否符合银行满减条件(如招行信用卡满100减10)
- 满减规则服务:判断订单金额是否满足满减条件(如满200减30)
- 价格计算服务:综合所有优惠后计算最终支付金额
若这些组件直接交互,会形成复杂的依赖关系(如优惠券服务需调用积分服务判断是否可叠加使用),新增优惠类型(如会员折扣)时需修改多个组件。使用中介者模式可通过营销中介者统一协调各组件,实现优惠规则的集中管理。
2. 设计实现
2.1 抽象中介者与同事类
import java.math.BigDecimal;
/**
* 营销中介者接口
*/
public interface MarketingMediator {
/**
* 注册营销组件
*/
void register(MarketingColleague colleague);
/**
* 协调计算优惠后金额
*/
BigDecimal calculateFinalAmount(PaymentContext context);
/**
* 应用所有优惠(扣减优惠券、积分等)
*/
void applyAllPromotions(PaymentContext context);
}
/**
* 营销同事类接口
*/
public abstract class MarketingColleague {
protected MarketingMediator mediator;
protected String promotionType; // 优惠类型(如COUPON、POINT、BANK)
public MarketingColleague(MarketingMediator mediator, String promotionType) {
this.mediator = mediator;
this.promotionType = promotionType;
}
/**
* 计算本组件可抵扣的金额
*/
public abstract BigDecimal calculateDeduction(PaymentContext context);
/**
* 应用本组件的优惠(如扣减优惠券)
*/
public abstract void applyPromotion(PaymentContext context);
public String getPromotionType() {
return promotionType;
}
}
2.2 具体营销组件(同事类)
/**
* 优惠券组件
*/
public class CouponColleague extends MarketingColleague {
public CouponColleague(MarketingMediator mediator) {
super(mediator, "COUPON");
}
@Override
public BigDecimal calculateDeduction(PaymentContext context) {
// 验证并计算可抵扣的优惠券金额
String couponId = context.getCouponId();
if (couponId == null || couponId.isEmpty()) {
return BigDecimal.ZERO;
}
// 实际中会调用优惠券服务查询面额并验证有效性
return new BigDecimal("20"); // 假设优惠券面额20元
}
@Override
public void applyPromotion(PaymentContext context) {
// 扣减优惠券(调用优惠券服务标记为已使用)
System.out.printf("应用优惠券%s,抵扣金额:%s%n",
context.getCouponId(), calculateDeduction(context));
}
}
/**
* 积分组件
*/
public class PointColleague extends MarketingColleague {
public PointColleague(MarketingMediator mediator) {
super(mediator, "POINT");
}
@Override
public BigDecimal calculateDeduction(PaymentContext context) {
// 计算积分可抵扣金额(100积分=1元)
int points = context.getUserPoints(); // 从上下文获取用户积分
return new BigDecimal(points).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_DOWN);
}
@Override
public void applyPromotion(PaymentContext context) {
BigDecimal deduction = calculateDeduction(context);
int pointsUsed = deduction.multiply(new BigDecimal("100")).intValue();
System.out.printf("使用积分%d,抵扣金额:%s%n", pointsUsed, deduction);
// 调用积分服务扣减积分
}
}
/**
* 银行活动组件
*/
public class BankActivityColleague extends MarketingColleague {
public BankActivityColleague(MarketingMediator mediator) {
super(mediator, "BANK");
}
@Override
public BigDecimal calculateDeduction(PaymentContext context) {
// 检查银行活动(如招行信用卡满100减10)
String bankCardType = context.getBankCardType();
BigDecimal amount = context.getOriginalAmount();
if ("CMB_CREDIT".equals(bankCardType) && amount.compareTo(new BigDecimal("100")) >= 0) {
return new BigDecimal("10"); // 满100减10
}
return BigDecimal.ZERO;
}
@Override
public void applyPromotion(PaymentContext context) {
BigDecimal deduction = calculateDeduction(context);
if (deduction.compareTo(BigDecimal.ZERO) > 0) {
System.out.printf("应用银行优惠,抵扣金额:%s%n", deduction);
// 通知银行活动服务记录优惠使用
}
}
}
/**
* 满减规则组件
*/
public class FullReductionColleague extends MarketingColleague {
public FullReductionColleague(MarketingMediator mediator) {
super(mediator, "FULL_REDUCTION");
}
@Override
public BigDecimal calculateDeduction(PaymentContext context) {
// 满减规则:满200减30,满500减80
BigDecimal amount = context.getOriginalAmount();
if (amount.compareTo(new BigDecimal("500")) >= 0) {
return new BigDecimal("80");
} else if (amount.compareTo(new BigDecimal("200")) >= 0) {
return new BigDecimal("30");
}
return BigDecimal.ZERO;
}
@Override
public void applyPromotion(PaymentContext context) {
BigDecimal deduction = calculateDeduction(context);
if (deduction.compareTo(BigDecimal.ZERO) > 0) {
System.out.printf("应用满减优惠,抵扣金额:%s%n", deduction);
}
}
}
2.3 具体中介者实现
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* 营销中介者实现类
*/
public class MarketingMediatorImpl implements MarketingMediator {
private List<MarketingColleague> colleagues = new ArrayList<>();
@Override
public void register(MarketingColleague colleague) {
colleagues.add(colleague);
}
@Override
public BigDecimal calculateFinalAmount(PaymentContext context) {
BigDecimal originalAmount = context.getOriginalAmount();
BigDecimal totalDeduction = BigDecimal.ZERO;
// 1. 计算所有优惠的总抵扣金额
for (MarketingColleague colleague : colleagues) {
BigDecimal deduction = colleague.calculateDeduction(context);
totalDeduction = totalDeduction.add(deduction);
}
// 2. 确保抵扣后金额不小于0
BigDecimal finalAmount = originalAmount.subtract(totalDeduction);
if (finalAmount.compareTo(BigDecimal.ZERO) < 0) {
finalAmount = BigDecimal.ZERO;
}
// 3. 保存计算结果到上下文
context.setTotalDeduction(totalDeduction);
context.setFinalAmount(finalAmount);
return finalAmount;
}
@Override
public void applyAllPromotions(PaymentContext context) {
// 按优先级应用优惠(如先满减,再优惠券,最后积分)
for (MarketingColleague colleague : getSortedColleagues()) {
colleague.applyPromotion(context);
}
// 输出最终结果
System.out.printf("原价:%s,总优惠:%s,实付金额:%s%n",
context.getOriginalAmount(),
context.getTotalDeduction(),
context.getFinalAmount());
}
// 按优先级排序营销组件
private List<MarketingColleague> getSortedColleagues() {
// 实际中可通过配置定义优先级,这里简化为固定顺序
List<MarketingColleague> sorted = new ArrayList<>();
for (MarketingColleague c : colleagues) {
if ("FULL_REDUCTION".equals(c.getPromotionType())) sorted.add(0, c);
else if ("COUPON".equals(c.getPromotionType())) sorted.add(1, c);
else if ("BANK".equals(c.getPromotionType())) sorted.add(2, c);
else if ("POINT".equals(c.getPromotionType())) sorted.add(3, c);
}
return sorted;
}
}
2.4 上下文与客户端使用
import java.math.BigDecimal;
/**
* 支付上下文(存储支付相关信息)
*/
public class PaymentContext {
private String orderId;
private BigDecimal originalAmount; // 原始金额
private String userId;
private String couponId; // 优惠券ID
private int userPoints; // 用户积分
private String bankCardType; // 银行卡类型
private BigDecimal totalDeduction; // 总优惠金额
private BigDecimal finalAmount; // 最终支付金额
// getter和setter方法...
}
/**
* 支付服务(客户端)
*/
public class PaymentService {
public void processPayment() {
// 1. 创建上下文并设置支付信息
PaymentContext context = new PaymentContext();
context.setOrderId("ORD20240501001");
context.setOriginalAmount(new BigDecimal("250")); // 原价250元
context.setUserId("USER123");
context.setCouponId("CPN886"); // 使用优惠券
context.setUserPoints(500); // 用户有500积分(可抵扣5元)
context.setBankCardType("CMB_CREDIT"); // 招行信用卡
// 2. 创建营销中介者并注册组件
MarketingMediator mediator = new MarketingMediatorImpl();
mediator.register(new CouponColleague(mediator));
mediator.register(new PointColleague(mediator));
mediator.register(new BankActivityColleague(mediator));
mediator.register(new FullReductionColleague(mediator));
// 3. 计算最终支付金额
mediator.calculateFinalAmount(context);
// 4. 应用所有优惠
mediator.applyAllPromotions(context);
}
public static void main(String[] args) {
new PaymentService().processPayment();
}
}
3. 模式价值体现
- 集中管理优惠规则:所有优惠的计算和应用逻辑由中介者协调,避免营销组件间的直接依赖(如优惠券无需判断是否可与积分同时使用)
- 灵活扩展新优惠:新增会员折扣只需添加
MemberDiscountColleague并注册到中介者,无需修改现有组件,符合开闭原则 - 统一优惠优先级:中介者控制优惠应用顺序(如先满减后用券),避免组件各自为政导致的规则冲突
- 简化组件职责:各营销组件只需实现自身的优惠计算和应用逻辑,无需关心其他组件的存在,代码更简洁
- 便于规则调整:修改优惠叠加规则(如禁止银行补贴与满减同时使用)只需修改中介者的
calculateFinalAmount方法,无需改动组件
五、开源框架中中介者模式的运用
在开源框架中,Spring MVC的DispatcherServlet是中介者模式的经典实现。作为前端控制器,它集中协调请求处理流程中的所有核心组件,避免组件间形成直接依赖,完美体现了"集中交互、解耦依赖"的设计思想。
1. DispatcherServlet的中介者角色定位
Spring MVC的请求处理涉及多个核心组件(同事类):
- HandlerMapping:根据请求查找对应的处理器(Handler)
- HandlerAdapter:适配不同类型的处理器(如注解式Controller、HttpRequestHandler)
- HandlerExceptionResolver:处理请求过程中的异常
- ViewResolver:将逻辑视图名解析为具体视图对象
- ModelAndView:封装处理器返回的模型数据和视图信息
DispatcherServlet作为中介者,承担以下核心职责:
- 接收客户端所有请求,作为唯一入口
- 协调各组件按序完成请求处理(路由→适配→执行→异常处理→视图渲染)
- 维护组件间的交互规则,屏蔽组件间的直接依赖
2. 核心代码实现分析
以下基于Spring MVC源码简化实现,重点展示DispatcherServlet如何作为中介者协调各组件:
2.1 抽象中介者与同事类接口
Spring MVC通过接口定义组件交互规范(类似抽象中介者和抽象同事类):
// 处理器映射接口(同事类)
public interface HandlerMapping {
// 根据请求查找处理器
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
// 处理器适配器接口(同事类)
public interface HandlerAdapter {
// 判断是否支持当前处理器
boolean supports(Object handler);
// 执行处理器,返回模型和视图
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}
// 视图解析器接口(同事类)
public interface ViewResolver {
// 解析视图名
View resolveViewName(String viewName, Locale locale) throws Exception;
}
// 异常处理器接口(同事类)
public interface HandlerExceptionResolver {
// 处理异常
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex);
}
2.2 具体中介者:DispatcherServlet
DispatcherServlet作为具体中介者,持有所有同事类的引用,并实现核心协调逻辑:
public class DispatcherServlet extends HttpServlet {
// 同事类引用集合
private List<HandlerMapping> handlerMappings;
private List<HandlerAdapter> handlerAdapters;
private List<HandlerExceptionResolver> handlerExceptionResolvers;
private List<ViewResolver> viewResolvers;
// 初始化:从Spring容器中获取所有组件(同事类)
@Override
protected void initStrategies(ApplicationContext context) {
// 初始化处理器映射器
handlerMappings = context.getBeansOfType(HandlerMapping.class).values().stream()
.collect(Collectors.toList());
// 初始化处理器适配器
handlerAdapters = context.getBeansOfType(HandlerAdapter.class).values().stream()
.collect(Collectors.toList());
// 初始化异常处理器
handlerExceptionResolvers = context.getBeansOfType(HandlerExceptionResolver.class).values().stream()
.collect(Collectors.toList());
// 初始化视图解析器
viewResolvers = context.getBeansOfType(ViewResolver.class).values().stream()
.collect(Collectors.toList());
}
// 核心方法:处理所有请求
@Override
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 1. 中介者协调第一步:通过HandlerMapping查找处理器
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 2. 中介者协调第二步:通过HandlerAdapter适配处理器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 3. 中介者协调第三步:执行处理器(通过适配器)
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
} catch (Exception ex) {
// 4. 中介者协调第四步:异常处理
dispatchException = ex;
mv = processHandlerException(processedRequest, response, mappedHandler, ex);
}
// 5. 中介者协调第五步:渲染视图
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
// 查找处理器(协调HandlerMapping)
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : handlerMappings) {
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
// 获取处理器适配器(协调HandlerAdapter)
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : handlerAdapters) {
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler");
}
// 处理异常(协调HandlerExceptionResolver)
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
for (HandlerExceptionResolver resolver : handlerExceptionResolvers) {
ModelAndView mv = resolver.resolveException(request, response, handler, ex);
if (mv != null) {
return mv;
}
}
throw ex; // 未处理的异常
}
// 渲染视图(协调ViewResolver)
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv,
Exception exception) throws Exception {
if (mv != null && !mv.wasCleared()) {
// 解析视图
View view = resolveViewName(mv.getViewName(), mv.getModelInternal(),
LocaleContextHolder.getLocale(), request);
// 渲染视图
view.render(mv.getModelInternal(), request, response);
}
}
// 解析视图名
private View resolveViewName(String viewName, Map<String, Object> model,
Locale locale, HttpServletRequest request) throws Exception {
for (ViewResolver viewResolver : viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
return null;
}
}
2.3 同事类具体实现(示例)
以最常用的注解式处理器相关组件为例,展示同事类的实现:
// 具体同事类:RequestMappingHandlerMapping(处理@RequestMapping注解)
public class RequestMappingHandlerMapping implements HandlerMapping {
@Override
public HandlerExecutionChain getHandler(HttpServletRequest request) {
// 根据请求路径匹配@Controller中的@RequestMapping方法
String path = request.getRequestURI();
Object handler = findHandlerByPath(path); // 内部逻辑:匹配处理器
return new HandlerExecutionChain(handler);
}
}
// 具体同事类:RequestMappingHandlerAdapter(适配注解式处理器)
public class RequestMappingHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
// 支持带@RequestMapping的方法处理器
return handler instanceof HandlerMethod &&
((HandlerMethod) handler).hasMethodAnnotation(RequestMapping.class);
}
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 执行处理器方法(如Controller的方法)
HandlerMethod handlerMethod = (HandlerMethod) handler;
Object result = handlerMethod.invoke(); // 反射调用方法
return new ModelAndView("viewName", "model", result); // 封装结果
}
}
// 具体同事类:InternalResourceViewResolver(解析JSP视图)
public class InternalResourceViewResolver implements ViewResolver {
@Override
public View resolveViewName(String viewName, Locale locale) {
// 将逻辑视图名解析为JSP路径(如"index"→"/WEB-INF/views/index.jsp")
return new InternalResourceView("/WEB-INF/views/" + viewName + ".jsp");
}
}
3. 中介者模式在DispatcherServlet中的体现
| 中介者模式角色 | Spring MVC对应实现 | 核心交互逻辑 |
|---|---|---|
| 抽象中介者 | 无显式接口(通过Servlet规范定义行为) | 定义请求处理的抽象流程 |
| 具体中介者 | DispatcherServlet | 持有所有组件引用,协调执行请求处理全流程 |
| 抽象同事类 | HandlerMapping、HandlerAdapter等接口 | 定义组件的抽象行为(如getHandler、handle) |
| 具体同事类 | RequestMappingHandlerMapping、RequestMappingHandlerAdapter等 | 实现具体业务逻辑,通过中介者交互 |
4. 模式价值分析
DispatcherServlet作为中介者,为Spring MVC带来以下核心价值:
- 彻底解耦组件依赖 各组件(HandlerMapping、HandlerAdapter等)无需知道其他组件的存在,只需专注自身职责。例如,HandlerMapping只需返回处理器,无需关心后续如何适配执行;ViewResolver只需解析视图,无需知道请求来源。
- 集中控制请求流程 所有请求处理步骤(路由→适配→执行→异常→渲染)由DispatcherServlet统一调度,流程清晰可控。新增步骤(如请求日志记录)只需修改中介者,无需改动组件。
- 灵活扩展组件 新增处理器类型(如响应式处理器)只需实现对应的HandlerAdapter;新增视图类型(如JSON、Excel)只需实现ViewResolver,无需修改DispatcherServlet,完美符合开闭原则。
- 简化开发复杂度 开发者无需关心组件间的交互细节,只需按规范实现组件(如用@RequestMapping定义处理器),由中介者自动协调,降低使用门槛。
通过DispatcherServlet的设计可以看出,中介者模式特别适合处理"多组件协同完成复杂流程"的场景,在框架设计中能显著提升系统的灵活性和可维护性。这一思想也可直接借鉴到支付框架的跨服务协同设计中(如前文的营销中介者)。
六、总结
1. 中介者模式的适用场景
- 当系统中存在多个对象需要频繁交互,形成复杂网状依赖时
- 当希望集中管理对象间的交互规则,避免规则分散在各个对象中时
- 当需要简化对象职责,使对象专注于自身业务而非交互逻辑时
- 当需要灵活扩展交互规则,或新增交互参与者时
2. 中介者模式与其他模式的区别
- 与观察者模式:两者都涉及对象间的通信,但观察者模式是“一对多”的通知机制(主题通知观察者),中介者模式是“多对多”的交互协调(中介者主动协调),前者是“被动通知”,后者是“主动协调”
- 与外观模式:外观模式为子系统提供统一接口,侧重简化子系统访问,中介者模式侧重协调子系统内部对象的交互,前者是“接口封装”,后者是“交互协调”
- 与代理模式:代理模式为单个对象提供代理,中介者模式协调多个对象的交互,前者是“对象代理”,后者是“多对象协调”
3. 支付系统中的实践价值
- 简化复杂协同场景:支付涉及的营销、风控、渠道等组件通过中介者协调,降低系统复杂度
- 提高可维护性:交互规则集中在中介者,便于调试和修改(如调整优惠计算逻辑)
- 加速业务迭代:新增支付功能(如跨境支付的税费计算)只需扩展中介者,现有组件无需改动
- 降低团队协作成本:不同组件可由不同团队开发,通过中介者接口约定交互方式,减少沟通成本
4. 实践建议
- 避免中介者膨胀:当中介者职责过多时,可按功能拆分(如将营销中介者拆分为优惠计算中介者和优惠应用中介者)
- 明确中介者与同事类的职责边界:中介者只负责协调,不处理具体业务逻辑;同事类只处理自身业务,不处理交互
- 使用配置驱动规则:将交互规则(如优惠优先级)存入配置中心,中介者通过配置动态协调,避免硬编码
- 结合事件驱动:复杂场景下,中介者可通过事件总线(如Spring Event)接收和发布事件,降低中介者与同事类的直接依赖
中介者模式通过“集中协调交互”的思想,有效解决了支付系统中多组件协同的复杂性,既降低了系统耦合度,又提高了业务扩展的灵活性,是构建复杂支付框架不可或缺的设计模式。