命令模式和策略模式、责任链模式有什么区别?
简化版
命令模式关注把请求封装成对象,便于排队、撤销、重做和统一调度;策略模式关注封装算法,让算法可以替换;责任链模式关注多个处理器按链路依次尝试处理请求。命令是“请求对象化”,策略是“算法可替换”,责任链是“请求沿链传递”。
详细版
三者都属于行为型模式,但意图不同:
| 模式 | 核心意图 | 典型关键词 | 常见场景 |
|---|---|---|---|
| 命令模式 | 请求对象化 | execute、undo、队列、日志 | 撤销重做、异步任务、菜单按钮 |
| 策略模式 | 算法替换 | 算法族、运行时切换 | 支付方式、折扣规则、排序策略 |
| 责任链模式 | 请求传递 | handler chain、放行、拦截 | Filter、审批流、风控规则 |
如果一个操作需要被保存、排队、撤销,用命令模式;如果是同一个目标下换不同算法,用策略模式;如果请求要经过多个处理节点,用责任链模式。
完整版教学
一、命令模式看的是请求本身
命令模式把请求封装成对象:
interface Command {
void execute();
}
重点是让请求可以被管理。
例如:
- 点击菜单后执行命令;
- 命令放入队列异步执行;
- 命令保存到历史栈支持撤销;
- 命令写入日志用于审计。
命令模式关心的是“这次操作”。
二、策略模式看的是算法选择
策略模式把一组算法封装起来:
interface DiscountStrategy {
int calculate(int price);
}
不同策略实现不同算法:
- 满减策略;
- 会员折扣策略;
- 优惠券策略;
- 新人折扣策略。
调用方选择一种策略来完成同一类计算。
策略模式关心的是“用哪种算法”。
三、责任链模式看的是处理流程
责任链模式把多个处理器串起来:
AuthHandler -> RateLimitHandler -> LogHandler -> BusinessHandler
请求沿着链路传递,每个节点决定处理、拦截或继续传递。
它常用于:
- Web Filter;
- Spring Security 过滤链;
- 审批流程;
- 风控规则;
- 网关拦截器。
责任链关心的是“谁来处理、按什么顺序处理”。
四、从代码结构区分
命令模式通常有 execute(),命令对象可能被保存:
List<Command>
Deque<Command>
Queue<Command>
策略模式通常被上下文直接调用:
strategy.calculate();
责任链通常有下一个处理器:
handler.setNext(nextHandler);
handler.handle(request);
当然代码结构不是唯一判断标准,最终还是要看设计意图。
五、三者可以组合使用
真实系统里它们可能一起出现。
例如订单系统:
- 用命令模式封装“创建订单”“取消订单”;
- 用策略模式选择不同计价规则;
- 用责任链执行风控校验、库存校验、优惠券校验。
它们解决的是不同层面的问题,并不互斥。
六、面试中容易答错的点
很多人会说“命令模式和策略模式都是封装一个接口”,这太表面。
更准确的回答是:
- 策略封装可替换算法,一般立即调用;
- 命令封装一次请求,可以延迟、排队、记录、撤销;
- 责任链封装多个处理节点,强调链式传递。
七、常见误区与追问
区分三种模式要看变化轴,而不是都出现了接口和实现类。若支付动作要进入队列并可重试,它是命令;若结算算法在3种优惠规则间择一,它是策略;若风控请求依次经过5个检查器并可中止,它是责任链。同一系统可以让命令内部选择策略,再把命令交给处理链。
| 检查维度 | 判定依据 |
|---|---|
| 命令 | 对象化一次请求及其生命周期 |
| 策略/责任链 | 择一算法 / 依次传递处理 |
记忆钩子:命令看“这件事”,策略看“怎么做”,责任链看“谁来处理”。
- 误区:有 execute 方法的都是命令模式。 策略也可能叫 execute,必须看对象是否代表一次可调度请求。
- 追问:命令里能否持有策略? 可以,命令负责请求生命周期,策略负责执行算法,两种职责并不冲突。
- 误区:责任链一定会处理请求多次。 链可以在首个处理器命中后短路,也可以让多个节点依次处理。
- 追问:三者最关键的扩展点分别是什么? 命令扩展请求类型,策略扩展算法,责任链扩展或重排处理节点。
- 追问:面试代码如何快速证明区别? 指出调用端保存的是请求对象、候选算法还是 next 链接,并说明运行流程。
八、加强记忆
命令模式、策略模式、责任链模式的区别要从意图看:命令把请求变成对象,策略把算法变成对象,责任链把处理流程变成链。需要撤销排队选命令,需要替换算法选策略,需要多节点传递选责任链。