一、为什么前端需要设计模式?
-
代码复用:将解决特定问题的方案抽象成模式,可以在不同项目中反复使用。
-
解耦:降低代码模块之间的依赖关系,使得修改一个部分时,对其他部分的影响最小。
-
提高可维护性:模式化的代码结构清晰,命名规范,易于理解和后续维护。
-
提升沟通效率:当团队成员都熟悉设计模式时,说 “我们用单例模式来管理这个全局状态”,比解释一大段代码逻辑要高效得多。
-
应对复杂性:大型应用的状态管理、组件通信等问题,都需要成熟的模式来优雅地解决。
二、设计模式分类
前端设计模式主要分为三大类:
-
创建型模式:处理对象创建机制
-
结构型模式:处理对象组合和关系
-
行为型模式:处理对象间的通信和职责分配
三、创建型模式 (Creational Patterns)
这类模式关注对象的创建过程,旨在提供更灵活、解耦的创建方式,主要有单例、工厂、建造者、原型等模式。
| 模式 | 核心思想 | 前端应用场景 |
| 单例模式 (Singleton) | 保证一个类只有一个实例,并提供全局访问点。 | Vuex/Redux 的 store、全局事件总线、全局缓存、浏览器的 window 对象。 |
| 工厂模式 (Factory) | 封装对象的创建逻辑,根据条件创建不同类型的对象。 | 动态组件渲染(根据配置渲染不同组件)、API 请求工厂、表单元素生成器。 |
| 建造者模式 (Builder) | 将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。 | (在前端较少直接使用),但在配置复杂对象时可见其思想。例如,Chart.js 或 ECharts 中配置图表的复杂 options 对象,就是分步构建的。 |
| 原型模式 (Prototype) | 通过复制现有实例来创建新实例。 | JavaScript 本身就是基于原型的语言。Object.create() 是原型模式的直接实现。在需要创建大量相似对象时(如游戏中的敌人),可以通过克隆原型来提高性能。 |
五、结构型模式 (Structural Patterns)
这类模式关注类和对象的组合,以如何将类或对象组合成更大、更灵活的结构为目标。主要有装饰器、代理、适配器、组合、外观等模式。
| 模式 | 核心思想 | 前端应用场景 |
| 装饰器模式 (Decorator) | 动态地为对象添加新功能,而不改变其结构。 | React HOC (高阶组件)、Vue 的 mixins、为按钮添加 loading 状态、为函数添加日志记录功能。 |
| 代理模式 (Proxy) | 为其他对象提供一种代理以控制对这个对象的访问。 | Vue 3 的响应式系统 (reactive/ref) 使用 ES6 Proxy 实现数据劫持。图片懒加载(用一个代理元素占位,等条件满足再加载真实图片)。 |
| 适配器模式 (Adapter) | 将一个类的接口转换成客户希望的另外一个接口。 | 封装旧的 API 使其与新的代码库兼容(例如,将一个返回回调的旧 API 封装成返回 Promise 的新 API)。适配不同的第三方库接口。 |
| 组合模式 (Composite) | 将对象组合成树形结构以表示 “部分 - 整体” 的层次结构。 | 虚拟 DOM (Virtual DOM) 树就是典型的组合模式。React/Vue 组件树、文件系统结构。 |
| 外观模式 (Facade) | 为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用。 | jQuery 就是外观模式的典范,它将复杂的原生 DOM API 封装成简单易用的 $ 接口。封装一个复杂的 localStorage 操作模块,提供简单的 get/set/remove 方法。 |
六、行为型模式 (Behavioral Patterns)
这类模式关注对象之间的通信和职责分配,以解决如何更好地分配职责,实现对象间的高效通信为目标。主要有观察者、策略、状态、模板方法、迭代器、职责链等模式。
| 模式 | 核心思想 | 前端应用场景 |
| 观察者模式 (Observer) | 定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖者都会收到通知。 | DOM 事件监听 (addEventListener)、Vue 的响应式系统、Redux 的订阅发布机制、事件总线 (Event Bus)。 |
| 策略模式 (Strategy) | 定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换。 | 表单验证(根据不同字段类型使用不同的验证策略)、动画效果切换(根据用户选择使用不同的动画算法)、排序算法切换。 |
| 状态模式 (State) | 允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。 | 有限状态机 (FSM)。例如,一个 Tab 组件的状态(active, disabled, hover)及其对应的行为;一个播放器的状态(playing, paused, stopped)及其切换逻辑。 |
| 模板方法模式 (Template Method) | 在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。 | (在前端较少直接使用),但在框架设计中很常见。例如,React 的 Component 类提供了 render() 这个模板方法,子类必须实现它来定义自己的 UI。 |
| 迭代器模式 (Iterator) | 提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。 | JavaScript 的 for...of 循环、数组的 map, filter, reduce 等方法都使用了迭代器模式。Symbol.iterator 是迭代器的核心。 |
| 职责链模式 (Chain of Responsibility) | 为请求创建了一个接收者对象的链,并沿着这条链传递请求,直到有对象处理它为止。 | 事件冒泡是职责链模式的绝佳例子。一个事件从目标元素向上传播,直到被某个父元素的监听器处理。在表单验证中,将验证规则串联起来,依次执行。 |
六、如何学习设计模式
1、从理解问题开始:
不要为了用模式而用模式。先问自己,“我遇到的是什么问题?” 然后再思考,“哪个模式能优雅地解决这个问题?”
2、从熟悉的框架中寻找:
现代前端框架本身就是设计模式的集大成者。例如:React 中处处是组件化思想(组合模式)、HOC(装饰器模式)、状态管理(观察者模式)。Vue 的响应式系统(代理模式)、组件通信(观察者模式 / 事件总线)。Redux 是观察者模式和状态模式的完美结合。
3、动手实践:
尝试用不同的模式解决同一个小问题,对比它们的优劣。例如,实现一个简单的弹窗,可以分别用单例模式和工厂模式来实现,感受它们的不同。
七、写在最后 !!!
-
不要过度使用:设计模式是为了解决复杂问题的。对于简单的场景,直接编写清晰的代码即可,强行套用模式反而会让代码变得冗余和难以理解。
-
理解而非背诵:学习模式的核心是理解其背后的设计思想和解决的问题,而不是死记硬背代码实现。
-
关注现代框架中的模式:许多设计模式已经被现代前端框架(如 React, Vue, Angular)内置或抽象化了。学习这些框架的源码,是深入理解设计模式的绝佳途径
1110

被折叠的 条评论
为什么被折叠?



