← 返回题目列表

访问者模式和策略模式、命令模式有什么区别?

高频 困难 第 10 / 25 题 更新于 2026/07/28
访问者模式策略模式命令模式模式对比

简化版

策略模式封装可替换算法,关注“同一任务的不同算法”;命令模式封装请求,关注“请求对象化、排队、撤销”;访问者模式封装作用在对象结构上的操作,关注“稳定元素结构上新增多种操作”。

详细版

三者区别:

  • 策略模式:把算法族封装起来,运行时选择一种算法。
  • 命令模式:把一次请求封装成对象,支持执行、撤销、队列、日志。
  • 访问者模式:把对不同元素类型的操作封装成访问者。

判断方式:

  • 如果变化的是算法,例如不同折扣算法,用策略。
  • 如果变化的是请求动作,例如复制、粘贴、撤销,用命令。
  • 如果变化的是对一组对象结构的操作,例如导出、统计、校验,用访问者。

访问者模式通常需要元素提供 accept,策略和命令一般不要求被处理对象配合这种双分派结构。

完整版教学

一、策略模式关注算法替换

策略模式解决的是“同一个问题有多种做法”。例如支付计费、排序算法、促销折扣、路由选择。

上下文对象持有一个策略,运行时切换策略即可。策略通常处理同一种输入输出,不强调元素类型层级。

二、命令模式关注请求对象化

命令模式把动作封装成对象。命令对象通常包含执行者、参数和执行方法。

它适合撤销重做、任务队列、异步执行、宏命令、操作日志。例如编辑器的复制、粘贴、撤销,或者消息队列中的任务。

命令模式关心“动作如何被保存、执行、撤销”,不是关心对象结构上的多类型访问。

三、访问者模式关注对象结构操作

访问者模式的重点是:有一组不同类型元素,对它们要新增很多操作。

它需要元素参与分派,通过 accept 把元素真实类型交给访问者。它解决的是“操作维度扩展”。

四、常见误区与工程判断

面试官喜欢给一个需求让你选模式。例如“订单有多种优惠计算方式”,这更像策略;“把用户操作记录下来支持撤销”,这更像命令;“对语法树做类型检查、代码生成、格式化”,这更像访问者。

工程中不要只看类名,要看变化点。设计模式本质是在管理变化,变化点判断对了,模式才有意义。

五、三者最容易混淆的边界

访问者、策略、命令都能把行为封装成对象,但封装的维度不同。策略模式封装的是“同一个算法点的不同实现”,比如不同折扣算法;命令模式封装的是“一个可执行请求”,强调执行、撤销、排队、日志;访问者模式封装的是“作用在一组不同元素类型上的一整套操作”。

如果面试官给你一个场景:同一订单要选择不同计价规则,更像策略;用户点击按钮后要记录操作并支持撤销,更像命令;一组稳定对象要新增导出、统计、审计逻辑,更像访问者。不要只看“都有接口和实现类”,要看行为绑定在哪个变化点上。

回答时可以主动说:访问者通常需要元素配合 accept,策略一般由上下文选择算法,命令通常有 receiver 或执行目标。调用结构不同,说明它们解决的问题也不同。

还可以从对象协作方式进一步区分:策略通常不要求被处理对象实现 accept;命令通常关心 executeundo、队列和日志;访问者则要求元素主动接收访问者,并把自身类型交给 visitor。协作结构不同,是判断模式的硬证据。

六、用工程约束检验答案

策略替换一个算法,命令封装一次请求,访问者为一组异构元素定义操作矩阵。若有 3 种折扣算法选 1 种是策略;把“退款”排队和重试是命令;让审计逻辑分别处理员工、部门、项目才是访问者。

检查项核心判断工程含义
Strategy可替换算法族Context 选择一种算法
Command请求对象化支持队列、日志、撤销
Visitor异构元素上的横向操作accept + visit 双分派

把关键关系压缩成一条可复述的路径:

算法可切换 -> Strategy
请求要排队/撤销 -> Command
稳定元素族新增操作 -> Visitor
先识别问题,再选结构

三者都封装行为,但封装对象、调用链和变化轴不同,不能因为“把逻辑放进类”就混为一谈。

落地前可以再按下面 3 步复核:

  1. 先说明“Strategy”的核心机制:可替换算法族;再交代边界:Context 选择一种算法。
  2. 接着分析“Command”:请求对象化;不能遗漏对应代价或结果:支持队列、日志、撤销。
  3. 最后用“Visitor”检查方案:异构元素上的横向操作;验收时确认accept + visit 双分派。

这三项构成完整判断链:先讲清Strategy,再说明Command,最后用Visitor检验实现是否越界。

面试中若能给出违反“accept + visit 双分派”的反例,再说明修正办法,答案就从模式定义落到了可验证的工程决策。

七、常见误区与追问

  • 误区:只看到“Strategy”就认为方案成立。 必须同时说明核心机制“可替换算法族”和工程边界“Context 选择一种算法”。
  • 误区:把“Command”当成无条件结论。 只有在“请求对象化”成立时,才能据此讨论“支持队列、日志、撤销”。
  • 追问:访问者能在运行时切换吗? 能传入不同访问者,但这不等于它的核心问题是算法替换。
  • 追问:命令也能撤销,和访问者有关吗? 命令围绕请求及逆操作,访问者围绕元素类型分派。
  • 追问:策略需要 accept 吗? 不需要,Context 通常直接调用统一策略接口。
  • 追问:命令能访问多种接收者吗? 能,但它封装的是一次请求,不要求为每种元素声明 visit 重载。
  • 追问:何时可能组合? 命令可携带一个访问者,对对象结构执行可排队的批量操作。

八、加强记忆

记忆时抓住这条主线:策略封装算法;命令封装请求;访问者封装对象结构上的操作;选模式先看变化点,不看名字。面试回答先给出模式意图,再用调用链或数据流说明角色协作,最后主动交代适用边界与工程代价。