行为型模式

共 17 题
📑 题目列表 17 题
#
★★★

1. 策略模式(Strategy)在表单校验链与权限规则链的工程价值

策略模式如何用于表单校验链与权限规则链?其工程价值是什么?

  • 策略模式封装可替换的算法族
  • 表单校验规则、权限规则可配置可扩展
  • 消除大量 if/else

策略模式定义一组可互相替换的算法(策略),并将每个策略封装成独立对象,客户端通过选择策略来改变行为,从而替代大量 if/else。在表单校验中,每种校验规则(必填、邮箱、长度、正则)是一个策略,通过规则名映射到对应校验函数,实现校验规则的可配置与可扩展;在权限规则链中,每种权限判定(角色、资源、时间)是一个策略,按需组合判定。工程价值在于:消除分支爆炸、规则可配置化(数据驱动)、新增规则只需新增策略不改动逻辑、便于单测与复用。实现上常配合映射表(策略表)与工厂,将规则名到策略函数解耦。需注意策略数量过多时应考虑用配置表与动态注册管理,避免策略类膨胀。

策略模式的核心是"把算法封装成可替换对象,用组合替代分支"。回答应结合表单校验与权限判定两个典型场景,说明如何用策略表消除 if/else、使规则可配置可扩展,并强调其开闭原则价值。

#
★★★

2. 观察者模式与发布订阅模式在前端状态管理与事件流的工程取舍

观察者模式与发布订阅模式有何区别?在前端状态管理与事件流中如何取舍?

  • 观察者模式(目标直接通知依赖者)
  • 发布订阅模式(中间事件总线解耦)
  • 状态管理(Vuex/Redux)与事件总线场景

观察者模式中,目标(Subject)直接持有观察者列表并 notify 通知,观察者与目标存在直接关联;而发布订阅模式在发布者与订阅者之间引入"事件总线/消息中心"作为中转,两者完全解耦,只通过事件名通信。前端状态管理多用观察者变体:Vue 的响应式系统、Redux 的 store 变更通知(subscribe)都是观察者思想,目标直接通知依赖方;事件总线(EventBus、mitt)则是发布订阅的典型,用于跨组件、跨模块的松散通信。工程取舍:发布订阅解耦更彻底、适合跨模块事件流,但事件名缺少类型约束、难以追踪、易泄漏(需手动 off);观察者关联更明确、便于调试与类型检查,但目标与观察者耦合较强。状态管理更倾向可预测的观察者/单向数据流,而解耦的临时事件用事件总线更合适。工程上需为事件总线建立事件定义与清理机制(unsubscribe),避免内存泄漏。

本题考察两种模式的本质区别与取舍。回答要清晰区分"目标直接通知依赖者"(观察者)与"经由中间总线解耦通信"(发布订阅),并结合状态管理(强关联、可预测)与事件流(松散解耦)说明各自适用场景与泄漏风险。

#
★★★

3. 备忘录模式(Memento)在撤销重做与时间旅行的实现

备忘录模式如何实现撤销/重做与时间旅行?在 Redux 等状态管理中如何应用?

  • 备忘录保存对象状态快照
  • 撤销/重做栈管理
  • 时间旅行(Redux DevTools)

备忘录模式在不破坏封装的前提下,将对象的状态保存为快照,在需要时恢复,从而支持撤销/重做。前端撤销重做通常实现为"状态快照栈"或"命令栈":每步操作前把当前状态压入撤销栈,撤销时把当前状态压入重做栈并从撤销栈取出恢复;新操作会清空重做栈。Redux 的时间旅行是其典型应用:action 是不可变的状态变更记录,Redux DevTools 通过记录 action 序列,可回溯到任意历史状态(跳转、回放),本质上是一份"状态备忘录"序列。实现要点:状态需不可变(immutable)才能安全保存快照而无需深拷贝,可用 Object.freeze、Immer 等保证;快照栈需限制容量(如最多 100 步)防止内存膨胀;恢复时需触发重新渲染。备忘录模式的价值在于让"可回退"成为状态管理的核心能力。

本题连接"备忘录模式"与"状态管理时间旅行"。回答要说明快照保存/恢复的机制、撤销/重做双栈管理,并结合 Redux 的不可变 action 与 DevTools 时间旅行说明实现,强调不可变性与栈容量限制。

#
★★★

4. 模板方法在框架生命周期钩子的应用

模板方法模式如何体现在框架的生命周期钩子中?其工程价值是什么?

  • 模板方法定义算法骨架、子类实现步骤
  • 生命周期钩子(onMounted、componentDidMount 等)
  • 框架提供可扩展点

模板方法模式在一个模板方法中定义算法的骨架,把某些步骤推迟到子类实现,从而让"流程固定、细节可定制"。Vue/React 的生命周期钩子正是模板方法思想的体现:框架定义了组件从创建、挂载、更新到销毁的完整流程骨架,并通过钩子(Vue 的 beforeCreate/onMounted、React 的 componentDidMount/useEffect)暴露可扩展点,让开发者在不改变框架流程的前提下注入自己的逻辑。工程价值在于:保证流程的稳定性与一致性、提供清晰的扩展点、将"固定流程"与"可变逻辑"分离,避免开发者破坏关键步骤。实现上,框架内部以固定顺序调用各钩子,子类只需覆写需要的钩子。这与观察者/事件机制不同——模板方法强调"框架主导流程、调用方填空",是框架设计"控制反转"(IoC)的体现。

模板方法的核心是"流程骨架 + 可覆写步骤"。回答要说明生命周期钩子如何让框架定义流程、调用方注入逻辑,并点出其在"控制反转"与"扩展点设计"中的价值,与单纯事件回调相区别。

#
★★★

5. 责任链模式在中间件、拦截器、Pipeline 的应用

责任链模式如何应用在中间件、拦截器与 Pipeline 中?其工程价值是什么?

  • 责任链将请求沿链传递处理
  • 中间件(Koa/Express)、拦截器、Pipeline
  • 每个节点决定继续或终止

责任链模式把多个处理对象连成一条链,请求沿链传递,每个处理者决定"是自己处理还是传给下一个",从而把"由一个处理者决定整条逻辑"变为"松散组织多个处理者"。前端典型应用:中间件——Koa/Express 的中间件链、Redux 的 applyMiddleware 用责任链包装 dispatch,每个中间件处理请求并可调用 next 传给下一个;拦截器——axios 的请求/响应拦截器、Vue Router 的导航守卫按顺序执行;Pipeline——数据处理流水线依次处理。价值在于:处理逻辑可动态增删、职责单一、链式可组合、插拔式扩展。实现上每个节点需显式调用 next 或终止,注意链的顺序与"是否放行"的决策。责任链让"复杂处理流程"拆成可独立维护的节点,契合可扩展与关注点分离。

责任链的核心是"链式传递 + 每节点决定继续或终止"。回答要结合中间件、拦截器、Pipeline 说明节点如何组织与放行,并强调整体流程可动态编排、易于扩展的价值。

#
★★

6. 迭代器模式(Iterator Pattern)在 ES6 Iterator 与 Generator 的原生支持

ES6 的原生 Iterator 与 Generator 如何体现迭代器模式?它们的工程价值是什么?

  • 迭代器协议(Symbol.iterator、next())
  • Generator 语法(yield)生成迭代器
  • 遍历统一(for...of、展开运算符)

迭代器模式提供一种顺序访问集合元素而不暴露内部结构的方式。ES6 原生支持迭代器协议:对象实现 Symbol.iterator 并返回 { next() { ... } } 即可被 for...of、展开运算符、解构等统一遍历,从而屏蔽遍历细节。Generator 是迭代器的便捷生成方式:function* 配合 yield 可暂停恢复执行,返回的 Generator 对象天然是迭代器,可以按需(惰性)生成序列,适合处理无限序列、流式数据、异步流程。工程价值:统一遍历接口(数组、Map、Set、自定义对象都能 for...of)、惰性求值降低内存、配合 for...of 与 async iterator(for await...of)抽象异步数据流。手写迭代器用 Generator 可显著简化,是前端处理数据流与异步的核心能力。

本题考察原生迭代器与 Generator 对迭代器模式的内建支持。回答要说明迭代器协议、Generator 的惰性生成能力,以及统一遍历接口与异步迭代的价值,体现对 ES6 语言特性的理解。

#
★★

7. MVVM 模式在前端框架(Vue、React)的实现差异与工程取舍

MVVM 模式在 Vue 与 React 中如何实现?两者有何差异与取舍?

  • MVVM 的 ViewModel/双向绑定
  • Vue 的响应式 + 模板绑定 ViewModel
  • React 的组件化 + 单向数据流(更接近 MVC 变体)

MVVM 将 View(视图)、Model(业务数据)、ViewModel(视图状态与绑定逻辑)分离,核心是数据绑定与 ViewModel 自动同步视图。Vue 是 MVVM 的典型实现:模板是 View,组件的 data/computed 是 Model,而 Vue 实例/响应式系统充当 ViewModel,通过数据绑定与指令自动同步视图与数据,且支持 v-model 双向绑定。React 更多采用"单向数据流 + 组件化":组件即 View 与 ViewModel 的结合,通过 props 向下传、事件向上传,状态变化由框架重新渲染视图,没有原生双向绑定,更接近 MVC/Flux 变体。工程取舍:Vue 的 MVVM 双向绑定开发更直观、模板驱动,但隐式数据流在复杂场景下难追踪;React 的单向数据流更可预测、易调试、利于函数式状态管理,但需显式管理状态与渲染。两者都实现"视图与状态分离",只是在绑定方式与数据流方向上取舍不同。

本题考察 MVVM 在主流框架中的落地差异。回答要说明 Vue 作为典型 MVVM(双向绑定、模板驱动)与 React(单向数据流、组件化)的不同,并对比"直观 vs 可预测"的取舍,体现对框架设计哲学的理解。

#
★★

8. MVC 模式在现代 SPA 框架(React、Angular、Svelte)

MVC 模式在现代 SPA 框架(React、Angular、Svelte)中如何被重构与演化?

  • MVC 的 Model-View-Controller 分离
  • React 视图 + 状态管理 + 动作
  • Angular/Svelte 的组件化与数据流

传统 MVC 通过 Controller 协调 Model 与 View,但现代 SPA 框架普遍弱化传统的 Controller,转向组件化与单向数据流。React 采用"组件(View)+ 状态(Model)+ 事件处理/Reducer(Controller 的替代)",通过 props 与 state 管理、事件回调与 action 驱动状态变化,状态变化再触发视图重渲染,形成单向数据流。Angular 用组件 + 依赖注入 + RxJS 管理状态与行为,Svelte 在编译期把状态与 DOM 绑定,无需运行时虚拟 DOM。共同趋势是:把 MVC 的"可预测性"保留,但用更细粒度的组件、状态管理与数据流(Flux/Redux/Context)替代传统 Controller 的中心化协调。工程取舍:组件化提升复用与可维护性,单向数据流提升可预测性,代价是状态管理复杂度上升。现代框架更关注"数据流方向"而非严格的 MVC 分层。

本题考察 MVC 在现代框架中的演化。回答要说明传统 Controller 被组件、事件与状态管理替代的过程,并比较 React/Angular/Svelte 各自的数据流与状态方案,强调"单向数据流 + 组件化"这一现代趋势。

#
★★

9. 中介者模式(Mediator)在多组件与多模块协调(对话框、表单联动)中相较直接引用与全局事件总线的工程取舍?

中介者模式在多组件与多模块协调(对话框、表单联动)中,相比直接引用与全局事件总线有何取舍?

  • 中介者集中协调组件间通信
  • 直接引用耦合高、事件总线解耦但难追踪
  • 对话框、表单联动场景

中介者模式通过一个中介对象集中协调多个对象之间的交互,使对象之间不再互相直接引用,从而降低耦合。在表单联动、对话框、多组件协调中,中介者(如表单状态对象、协调器)统一管理组件间的状态同步与事件分发,组件只需与中介者交互。相比"直接引用":直接引用实现简单但形成网状耦合、难以维护;相比"全局事件总线":事件总线解耦彻底但事件名散落、难追踪、易泄漏。中介者居中权衡——它集中了协调逻辑,耦合度低于直接引用、可追踪性高于事件总线,适合"多个组件需要频繁联动"的场景,将网状通信收敛为"组件 ↔ 中介"的星状通信。取舍:中介者可能成为"上帝对象"(逻辑过于集中),必要时用更细粒度的存储(如表单 store)与显式数据流替代。工程上应结合状态管理(如 Vuex/Pinia store 作为中介)实现可控的联动。

本题要求对比三种协调方式。回答要说明中介者如何把"组件间直接引用"收敛为"组件与中介交互",并对比它与事件总线在可追踪性/耦合度上的取舍,同时点出中介者易变的"上帝对象"风险。

#
★★

10. 状态模式在前端状态机(XState)的应用

状态模式如何在前端状态机(如 XState)中应用?其工程价值是什么?

  • 状态模式将状态行为封装为独立对象
  • 状态机(State Machine)建模状态迁移
  • XState 提供显式状态图

状态模式把"不同状态下的行为"封装为独立对象,让对象在状态变化时切换行为,从而把复杂的 if/else 状态判断收敛为"状态 + 迁移"。状态机(State Machine)是状态模式的工程化表达:明确定义状态集合、触发事件与迁移规则,保证状态转移合法且可预测。XState 等库把状态机建模为可执行的状态图(StateChart),支持状态嵌套、并行状态、守卫(guard)、动作(action)与副作用,用于复杂业务流程(如表单流程、下单流程、异步加载状态)。工程价值:状态转移显式、避免非法状态、可测试、可可视化、减少散落的布尔标志(isLoading/isError)带来的状态组合爆炸。相比临时布尔标志,状态机让"状态全场唯一"、行为随状态封装,大幅提升复杂交互的可维护性。

本题考察状态模式与状态机的结合。回答要说明状态模式"按状态封装行为"的核心,以及状态机如何显式建模状态迁移,并结合 XState 与传统布尔标志的对比,突出其可预测性与可维护性。

#
★★

11. 访问者模式(Visitor)在 AST/组件树遍历的工程价值

访问者模式如何在 AST(抽象语法树)与组件树遍历中应用?其工程价值是什么?

  • 访问者分离数据结构与操作
  • AST 遍历(Babel、编译器)
  • 组件树遍历与递归处理

访问者模式将"对数据结构元素的操作"与"数据结构本身"分离,通过访问者在数据结构上遍历并对各类型元素执行对应操作,从而在不修改元素类的前提下新增操作。前端典型应用:AST 遍历——Babel、ESLint、编译工具用 visitor 在语法树节点上执行转换、检查、分析,每种节点类型对应一个 visit 方法;组件树遍历——对组件树做收集、统计、修改等操作时,用递归遍历并在节点类型上分发。工程价值:新增操作(如新增一个 lint 规则)只需新增访问者,无需修改 AST 节点类,符合开闭原则;遍历逻辑与操作逻辑分离,便于复用与测试。代价是访问者与元素结构耦合较紧、新增元素类型需更新所有访问者,且递归遍历在深树上有栈溢出风险(可用迭代栈)。访问者适合"结构稳定、操作多变"的场景,如编译器、代码分析。

本题考察访问者"数据结构与操作分离"的思想。回答要结合 AST 遍历(Babel/ESLint)与组件树遍历说明其"新增操作无需改结构"的价值,并点出正确性(栈溢出)与适用边界(结构稳定操作多变)。

#
★★

12. 解释器模式在前端 DSL、规则引擎的应用

解释器模式如何用于前端 DSL 与规则引擎?其工程价值是什么?

  • 解释器定义语法规则并解释执行
  • 前端 DSL(模板、表达式、查询语言)
  • 规则引擎(条件组合、脚本执行)

解释器模式为一种语言定义文法表示,并解释执行其中的语句,适合处理"可配置的规则/表达式"。前端典型应用:DSL——模板引擎的表达式语法、查询语言、JSON Schema 校验、公式解析;规则引擎——把可配置的规则(如 age > 18 && status === 'active')解析为可执行的结构,业务人员无需改代码即可调整规则。工程价值:规则/表达式可配置化、与代码解耦、便于动态更新与复用。实现方式分两种:直接解释 AST(先解析为语法树再遍历求值),或编译为可执行函数(如 new Function/eval,需注意安全)。工程上解释器本身可能复杂,前端常用现成方案(如 jsep 解析表达式、json-logic-js 做规则引擎)而非手写完整文法,并注意 CSP(内容安全策略)对 eval 等执行的限制。需注意安全边界:避免对不可信输入使用 eval/new Function,应做白名单与沙箱。

本题考察解释器模式与前端 DSL/规则引擎。回答要说明"解释并执行规则"的核心,结合表达式解析与规则引擎举例,并强调安全(避免 eval 注入)与"用现成库而非手写"的工程取舍。

#
★★

13. 命令模式在撤销重做、事务操作的应用

命令模式如何实现撤销重做与事务操作?其工程价值是什么?

  • 命令封装操作、参数与执行环境
  • 命令队列支持撤销/重做
  • 事务操作(批量执行、回滚)

命令模式将"请求"封装为独立对象,包含执行所需的信息(参数、接收者),并可支持撤销(undo)与重做(redo),从而把调用者与执行者解耦。前端典型应用:撤销重做——编辑器、画布、表单中的每步操作封装为命令,命令栈记录执行历史,撤销时调用 undo、重做时调用 redo;事务操作——把一组操作组合为一个命令,要么全部执行要么全部回滚,保证一致性。工程价值:操作可组合、可回滚、可记录、可延迟执行,调用者无需关心具体实现;命令对象可序列化与日志记录(便于重放与审计)。实现上命令需提供 execute 与 undo 方法,并保存撤销所需的状态快照或反向操作;撤销栈与重做栈配合管理。相比备忘录模式(保存状态快照),命令模式保存"操作本身",更精细且省内存,适合操作粒度清晰的场景。

本题考察命令模式与撤销/事务。回答要说明命令封装操作、支持 undo/redo 与事务,并对比备忘录模式(快照 vs 操作),突出命令模式在"操作粒度回滚"与"可组合"上的价值。

#

14. CQRS 模式在复杂表单(命令与查询分离)的工程实践

CQRS(命令与查询职责分离)模式如何应用于复杂表单?其工程实践是什么?

  • CQRS 分离命令(写操作)与查询(读操作)
  • 复杂表单的读写逻辑分离
  • 状态管理与表单数据流

CQRS(Command Query Responsibility Segregation)主张将系统的"写操作(命令)"与"读操作(查询)"分离,各自使用不同的模型与路径。在复杂表单中,CQRS 体现为:查询(Query)——展示表单当前值、校验状态、下拉选项等只读数据,通过选择器/派生状态读取;命令(Command)——提交、重置、保存、字段变更等写操作,通过 action/reducer 修改状态。工程实践:用 Redux/Vuex 时,表单"读"用 selector/mapGetters 派生,"写"用 action 提交,避免组件内直接改状态;命令可携带校验与业务规则,查询只返回所需数据。价值在于:读写关注点分离、模型各自优化(读可缓存、写可校验)、提升可维护性与可测试性。但需注意 CQRS 在纯前端单模型场景下可能过度设计,前端更常用的是"单向数据流 + 选择器"轻量化的分离,而非完整的 CQRS 加事件溯源。

本题考察 CQRS 在复杂表单的落地。回答要说明"读写分离"的核心思想与表单中的 Query/Command 划分,并强调前端常用轻量化的单向数据流与选择器实现,而非完整 CQRS 架构,避免过度设计。

#

15. Pipeline 模式在前端构建工具(Webpack、Vite)的应用

Pipeline 模式如何应用于 Webpack、Vite 等前端构建工具?其工程价值是什么?

  • Pipeline 串联多个处理阶段
  • Webpack 的 loader 链、plugin 钩子
  • Vite 的插件与转换管线

Pipeline(管线)模式把多个处理阶段按顺序串联,前一个阶段的输出作为后一个阶段的输入,形成可插拔的处理链。前端构建工具大量使用该模式:Webpack 的 loader 链——模块从源文件开始经过一系列 loader(如 ts-loader → babel-loader → css-loader)依次转换,最终产出可打包资源;Webpack 的 plugin 通过 tapable 钩子形成事件管线,在构建各阶段注入处理;Vite 基于 Rollup 插件与 esbuild 转换,把各类文件(TS、JSX、CSS、静态资源)经插件管线转换为目标格式。工程价值:处理阶段可插拔、可复用、可组合,构建流程可扩展而无需改动核心;每个阶段职责单一,便于测试与维护。loader/plugin 的"顺序"与"透传"语义与责任链相似,但 Pipeline 强调"顺序处理、结果传递",是构建工具扩展性的核心机制。

本题考察 Pipeline 在构建工具中的体现。回答要说明 loader 链与插件钩子如何形成顺序处理管线,突出"可插拔、可组合"的扩展性价值,并类比责任链的"顺序传递"。

#

16. Process Manager 模式在前端复杂业务流程编排的现代实践

Process Manager(流程管理器)模式如何编排前端复杂业务流程?现代实践有哪些?

  • Process Manager 编排多步骤/多任务流程
  • 复杂业务流程(下单、引导、异步编排)
  • 状态机、Promise 链、任务队列

Process Manager(流程管理器)模式集中管理复杂业务流程的编排,将多步骤、多状态、可能并行的任务组织成可执行、可追踪的流程,并协调各步骤的时机与数据。前端复杂业务流程(下单、注册引导、多阶段表单、异步任务编排)常需要流程管理器:它维护流程状态、步骤顺序、条件分支与失败处理。现代实践包括:结合状态机(XState)显式建模流程状态与迁移;用 Promise 链与 async/await、任务队列(如 p-queue)编排依赖的异步步骤;用可视化流程图工具(如 bpmn-js)编排可配置流程;用事件驱动的调度器分步执行。价值在于:把"散落的流程控制"集中为可管理的编排器,提升可读性、可测试性与可扩展性,支持取消、重试、超时与持久化。相比在组件里到处写流程逻辑,流程管理器让业务逻辑集中且可复用。

本题考察流程编排的现代实践。回答要说明流程管理器如何集中编排多步骤流程,并结合状态机、异步编排、任务队列等现代手段,突出其可管理、可测试、可扩展的价值。

#

17. 空对象模式(Null Object)在避免空值判断链(可选链与默认值)的工程应用与滥用边界?

空对象模式如何避免空值判断链?结合可选链与默认值,其工程应用与滥用边界是什么?

  • 空对象模式以"无操作对象"替代 null 判断
  • 可选链(?.)与默认值(??)的替代
  • 滥用边界与可读性

空对象模式以"什么都不做的空对象"替代 null 引用,让调用方无需逐层判断空值即可安全调用方法。例如缺省用户、空列表、空配置可用一个实现了同样接口但无操作的空对象表示,避免大量 if (obj && obj.a && obj.a.b)if (x) x.doSomething() 的判断。现代 JS 提供了更轻量的替代:可选链 ?. 在访问链中空值短路返回 undefined,空值合并 ?? 提供默认值,让部分空值判断更简洁。三者可配合:默认值处理用 ??,深层访问用 ?.,而空对象模式适合"需要统一行为/多态"的场景(如类型不同的空实现)。滥用边界:空对象可能掩盖逻辑错误(把 null 静默当作正常对象)、增加抽象层次、且对"必须区分空与非空"的场景(如表单校验需要明确空值)不适用。应优先用可选链与默认值处理简单空值,仅在需要多态行为或消除大量空判断时用空对象模式。

本题考察空对象模式与语言特性(可选链/默认值)的取舍。回答要说明空对象模式的"无操作替代"思想,对比 ?./?? 的轻量方案,并明确指出滥用边界——掩盖错误、过度抽象、需区分空值时不适用。