Skip to content

参考

基于 Refactoring.Guru + Node.js v26 / XState v5 / MDN 迭代协议官方文档编写

速查

  • 行为型 10 模式:责任链 / 命令 / 迭代器 / 中介者 / 备忘录 / 观察者 / 状态 / 策略 / 模板方法 / 访问者
  • 关注:对象间职责分配 + 通信算法(不涉及创建与结构装配)
  • JS 语言级内置:迭代器 Symbol.iterator、观察者 EventEmitter / EventTarget
  • XState v5createMachine + createActor().start()(替代 v4 interpret
  • undo/redo:双栈 + execute 前 saveBackup + 新命令清空 redoStack
  • 策略 vs 状态:策略由客户端切换 / 状态由状态对象自身切换
  • 责任链:setNext 返回 handler 支持链式,ConcreteHandler 要么处理要么传递
  • 访问者:双分派 accept(v)v.visitXxx(this),Babel/ESLint 插件即此模式
  • 详尽讲解见 入门 / 十模式深度讲解

十模式完整对比表

模式意图(一句话)关键角色前端典型落地主要反模式
责任链请求沿链传递,每个 Handler 决定处理或转交Handler / ConcreteHandler / ClientExpress/Koa middleware、axios interceptors链断裂(既不处理也不传递)
命令把请求封装成对象,支持 undo/redo 与排队Command / ConcreteCommand / Receiver / Invoker / History富文本 undo/redo、Redux dispatch单栈无法 redo、execute 前未 saveBackup
迭代器提供统一协议顺序遍历集合Iterable [Symbol.iterator]() / Iterator next()→{value,done}for...of / Generator / Map/Set/Array共享迭代器实例致状态互踩
中介者用中心对象协调多组件,消除网状依赖Mediator / ConcreteMediator / ComponentVue 3 mitt、对话框协调、Pinia 宏观中介God Mediator(中介者膨胀)
备忘录不破坏封装下保存与恢复对象内部状态Originator / 不可变 Memento / Caretaker编辑器撤销、表单草稿、游戏存档不限制历史长度致快照栈爆炸
观察者一对多依赖,目标变化自动通知所有订阅者Publisher / SubscriberEventEmitter / Redux store.subscribe / mitt / EventTarget未取消订阅致内存泄漏、通知风暴
状态状态变化时行为也跟着变,状态封装成独立类Context / State / ConcreteStateXState v5 状态机、订单/审批流、TCP 状态巨型 switch-case + 布尔标志位
策略一族可互换算法封装成独立类,运行时切换Context / Strategy / ConcreteStrategy表单校验器、排序规则、价格计算1-2 个变体硬套类层次(过度设计)
模板方法父类定义算法骨架,子类重写个别步骤AbstractClass(模板方法 + 抽象/可选/钩子步骤)/ ConcreteClassReact 类组件生命周期、构建管线子类重写模板方法破坏骨架
访问者不修改类的前提下为其新增操作(双分派)Element accept(v) / Visitor visitXxx(this)Babel/ESLint AST 插件、编译器语义分析用于变动结构(维护成本爆炸)

易混模式对比

策略 vs 状态(最高频考点)

维度策略状态
状态间感知互不感知可相互感知
主动切换方客户端 setStrategy()状态对象自身 context.changeState()
行为意图算法可互换状态驱动行为切换
数量可任意多通常有限(订单状态、连接状态等)
转换规则有(甚至有守卫 guards)
典型场景表单校验、排序订单流、TCP 连接、视频播放器

中介者 vs 观察者

维度中介者观察者
通信方式集中式(中心对象协调)分布式(发布者广播)
组件感知中介者知道每个组件身份只关心事件订阅
协调逻辑封装在中介者内部散落在订阅者
适用场景组件交互复杂、强协调跨组件解耦广播
关系与观察者可混合(EventBus)独立

责任链 vs 装饰器(结构型)

维度责任链(行为型)装饰器(结构型)
流向中断不可中断
意图分发职责增强功能
顺序决定处理或传递全程包裹

模板方法 vs 策略

维度模板方法策略
机制继承(重写方法)组合(持策略引用)
切换时机类级静态(编译期定)运行时可切换
骨架父类固定骨架无骨架概念
粒度整个算法流程单一算法

命令 vs 备忘录(undo 实现)

维度命令备忘录
关注操作的执行 + 撤销状态的保存 + 恢复
undo 实现execute() 反向操作restore 快照
配合命令常当 Caretaker备忘录提供快照存储

前端映射速查表

模式库 / 框架 / API映射点
观察者Node.js EventEmitteron/emit/once/off
观察者Redux store.subscribe拉模型 + getState
观察者浏览器 EventTarget / mitt / nanoevents事件总线
迭代器ES2015 Symbol.iterator + for...of语言级内置
迭代器Generator function* / yield迭代器语法糖
状态XState v5 createMachine / createActor状态机工程化
责任链Express / Koa middleware next()中间件链
责任链axios interceptors.request.use()拦截器链
命令Redux dispatch({type, payload})命令对象(无 undo 时退化成事件)
策略VeeValidate / Yup / Zod schema表单校验器
访问者Babel @babel/traverse 插件 visitorAST 节点遍历
访问者ESLint 规则 create 方法返回 visitorAST 节点遍历
中介者Pinia / Redux store宏观状态中介者
中介者Vue 3 mitt(替代 Vue 2 event bus)松散事件总线

三种步骤类型(模板方法)

步骤类型父类提供子类责任用途
抽象步骤仅声明 abstract必须实现强制子类提供关键步骤
可选步骤默认实现可重写给常见默认值,特殊情况可覆盖
钩子(Hook)空方法 / 默认布尔可选择性覆盖扩展点,默认不影响骨架

双分派图解(访问者)

text
普通多态(单分派):
  element.foo() → JS 根据 element 的实际类型调用对应 foo

访问者(双分派):
  element.accept(visitor)
    → 第 1 次分派:根据 element 实际类型决定调 visitUser/visitGroup/...
    → 第 2 次分派:根据 visitor 实际类型(PrintVisitor/ExportVisitor/...)
                  决定执行哪个具体实现

命令模式双栈图解

text
初始:undoStack=[]  redoStack=[]

执行 cmd1:
  cmd1.execute() → undoStack=[cmd1]  redoStack=[]  (清空!)

执行 cmd2:
  cmd2.execute() → undoStack=[cmd1,cmd2]  redoStack=[]

undo:
  pop undoStack=cmd2 → cmd2.undo() → push redoStack
  → undoStack=[cmd1]  redoStack=[cmd2]

redo:
  pop redoStack=cmd2 → cmd2.execute() → push undoStack
  → undoStack=[cmd1,cmd2]  redoStack=[]

undo 后执行新 cmd3:
  → undoStack=[cmd1,cmd3]  redoStack=[]  (清空 redoStack!避免分支错乱)

ES6 迭代协议要点

协议必须用法
Iterable[Symbol.iterator]() 返回 Iteratorfor...of 消费
Iteratornext() 返回 {value, done}手动遍历
Generatorfunction* + yield自动生成符合上述协议的对象
内置 IterableArray / Map / Set / String / TypedArray / NodeList / arguments直接 for...of

关键纪律:[Symbol.iterator]() 每次调用必须返回新迭代器,否则多个消费者共享状态互相踩。

XState v5 关键 API

API作用v4 → v5 差异
createMachine({...})声明状态机配置配置项兼容(states/on/target/actions/guards/context)
createActor(machine).start()创建并启动 actor 实例替代 v4 interpret(machine).start()
actor.subscribe(cb)订阅状态变化类似 v4 但返回 ActorSubscription
actor.send({type})发送事件触发转换与 v4 一致
assign(({ctx,event}) => ...)声明式 context 更新与 v4 一致

反模式清单(跨模式)

反模式模式后果解法
链断裂责任链请求静默丢失链尾兜底 + 显式 super.handle()
单栈 undo命令无法 redo双栈
execute 前 saveBackup 缺失命令undo 时无状态可恢复强制 execute 第一步抓快照
共享迭代器实例迭代器多消费者互相踩状态每次调用返回新迭代器
God Mediator中介者巨型类膨胀拆多个职责单一中介者
不限制历史长度备忘录快照栈无限增长限制 maxLen + 增量快照
未取消订阅观察者内存泄漏组件卸载必 unsubscribe
通知风暴观察者级联重渲染selector + 浅比较 / RxJS 节流
巨型 switch-case状态非法转换无防护、不可维护XState 声明式状态机
类爆炸(过度设计)策略/状态5+ 文件解决 1 个变体用高阶函数
重写模板方法模板方法破坏骨架一致性约定 + 注释禁重写
Visitor 用于变动结构访问者每加元素改所有 Visitor结构稳定才用 Visitor

版本与生态现状

取值备注
GoF 行为型模式1994 经典理论,无版本号语言无关、稳定不变
Node.js EventEmitter自 Node v0.1 稳定至今on/emit/once/removeListener 不变
ES6 迭代协议ES2015 标准化永久内置,无替代
XStatev5(v4 已进维护期)createActor 替代 interpret
Redux ToolkitRTK 取代手写 reducer底层 store.subscribe 机制不变
mitt~200B 事件总线Vue 3 推荐
nanoevents极简事件总线~93B
Vue 2 event-bus已移除Vue 3 用 mitt 或 props-down-events-up

官方资源