第一章:JavaScript设计模式概述
JavaScript设计模式是开发者在长期实践中总结出的可复用解决方案,用于应对常见的软件设计问题。这些模式不提供具体的代码实现,而是描述了一种解决问题的思想和结构,帮助提升代码的可维护性、可扩展性和可读性。
设计模式的核心价值
- 提高代码复用性,减少重复逻辑
- 增强模块间的解耦,便于团队协作
- 提供标准化的沟通语言,使架构讨论更高效
常见的设计模式分类
| 类型 | 典型模式 | 适用场景 |
|---|
| 创建型 | 单例、工厂、构造器 | 对象创建过程的封装与控制 |
| 结构型 | 装饰器、适配器、代理 | 对象组合或类继承的结构优化 |
| 行为型 | 观察者、策略、命令 | 对象间通信与职责分配 |
单例模式示例
// 确保一个类仅有一个实例,并提供全局访问点
class Singleton {
constructor() {
if (Singleton.instance) {
return Singleton.instance;
}
this.data = 'I am the only instance';
Singleton.instance = this;
}
getData() {
return this.data;
}
}
// 使用方式
const instance1 = new Singleton();
const instance2 = new Singleton();
console.log(instance1 === instance2); // true,引用同一实例
graph TD
A[客户端请求实例] --> B{实例是否存在?}
B -->|否| C[创建新实例并保存]
B -->|是| D[返回已有实例]
C --> E[返回实例]
D --> E
第二章:创建型设计模式核心解析
2.1 工厂模式的实现与应用场景
工厂模式是一种创建型设计模式,用于在不指定具体类的情况下创建对象。它通过定义一个创建对象的接口,由子类决定实例化哪一个类,从而实现松耦合。
简单工厂示例
type Product interface {
GetName() string
}
type ConcreteProductA struct{}
func (p *ConcreteProductA) GetName() string {
return "Product A"
}
type SimpleFactory struct{}
func (f *SimpleFactory) CreateProduct(typ string) Product {
if typ == "A" {
return &ConcreteProductA{}
}
return nil
}
上述代码中,
SimpleFactory 根据传入参数返回不同产品实例。调用者无需关心对象创建细节,仅依赖接口编程。
典型应用场景
- 需要根据不同配置生成对象时
- 对象创建逻辑复杂且需集中管理
- 希望屏蔽产品类的具体实现
2.2 单例模式的惰性加载与全局控制
在高并发系统中,单例模式通过惰性加载(Lazy Initialization)实现资源的按需创建,有效降低启动开销。该机制确保实例仅在首次被请求时初始化,结合线程安全控制,保障唯一性。
双重检查锁定实现
public class LazySingleton {
private static volatile LazySingleton instance;
private LazySingleton() {}
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
if (instance == null) {
instance = new LazySingleton();
}
}
}
return instance;
}
}
上述代码中,
volatile 关键字防止指令重排序,两次判空减少同步开销。首次调用时才创建实例,实现真正的惰性加载。
优势与适用场景
- 节省内存资源,延迟初始化开销
- 保证全局状态一致性
- 适用于配置管理、日志服务等高频访问对象
2.3 建造者模式解耦对象构造过程
在复杂对象的创建过程中,若直接使用构造函数或工厂模式,容易导致参数膨胀与职责混乱。建造者模式通过将构造逻辑分步封装,实现对象构建过程的解耦。
核心结构与角色分工
- Product:最终构建的复杂对象
- Builder:定义构建步骤的抽象接口
- ConcreteBuilder:实现具体构建逻辑
- Director:指挥构建流程,隔离使用与构造
代码示例:构建HTTP请求配置
type RequestConfig struct {
URL string
Timeout int
Headers map[string]string
Retries int
}
type ConfigBuilder interface {
SetURL(url string) ConfigBuilder
SetTimeout(seconds int) ConfigBuilder
AddHeader(key, value string) ConfigBuilder
SetRetries(n int) ConfigBuilder
Build() *RequestConfig
}
上述接口将配置项逐步设置,避免一次性传入大量可选参数。每个方法返回构建器自身,支持链式调用,提升代码可读性。最终由 Build() 方法完成对象组装,确保构造过程与表示分离。
2.4 原型模式利用克隆提升性能
原型模式通过复制现有对象来创建新实例,避免重复执行复杂初始化过程,显著提升性能。尤其在对象创建成本较高时,克隆机制尤为有效。
克隆实现方式
JavaScript 中可通过
Object.create() 或扩展运算符实现浅克隆:
const prototypeObj = { config: { timeout: 5000 }, init() { /* 初始化逻辑 */ } };
const clonedObj = Object.create(prototypeObj);
上述代码中,
clonedObj 继承原型方法与属性,无需重新定义配置结构。
性能对比
| 创建方式 | 耗时(ms) | 内存占用 |
|---|
| 构造函数初始化 | 12.4 | 高 |
| 原型克隆 | 2.1 | 低 |
克隆操作省去重复计算,适用于频繁实例化场景。
2.5 抽象工厂模式组织相关产品族
抽象工厂模式用于创建一组相关或相互依赖的对象,而无需指定具体类。它通过定义一个创建产品族的接口,使客户端与具体实现解耦。
核心结构
- 抽象工厂(Abstract Factory):声明创建一系列产品的方法
- 具体工厂(Concrete Factory):实现创建具体产品族的逻辑
- 抽象产品(Abstract Product):定义产品类型的接口
- 具体产品(Concrete Product):实际被创建的对象
代码示例
type GUIFactory interface {
CreateButton() Button
CreateCheckbox() Checkbox
}
type WinFactory struct{}
func (f *WinFactory) CreateButton() Button { return &WinButton{} }
func (f *WinFactory) CreateCheckbox() Checkbox { return &WinCheckbox{} }
上述代码定义了一个 GUI 抽象工厂,能够创建按钮和复选框。Windows 工厂实现了该接口,返回对应平台的具体控件实例,从而确保同一产品族内的对象协同工作。
第三章:结构型设计模式实战精讲
3.1 适配器模式兼容不匹配接口
在系统集成中,常遇到接口不兼容的问题。适配器模式通过封装现有接口,使其符合客户端期望的协议,实现无缝调用。
适配器结构设计
适配器模式包含三个核心角色:目标接口(Target)、被适配者(Adaptee)和适配器(Adapter)。适配器继承目标接口并持有被适配者实例,将请求转发并转换。
- 目标接口:定义客户端使用的标准方法
- 被适配者:已有但接口不兼容的类
- 适配器:桥接两者,实现接口转换
代码示例与解析
type Target interface {
Request()
}
type Adaptee struct{}
func (a *Adaptee) SpecificRequest() {
fmt.Println("Adaptee执行特殊请求")
}
type Adapter struct {
adaptee *Adaptee
}
func (a *Adapter) Request() {
a.adaptee.SpecificRequest() // 转换调用
}
上述代码中,
Adapter 实现了
Target 接口的
Request 方法,并在其内部调用
Adaptee 的
SpecificRequest,完成接口语义的映射与兼容。
3.2 装饰器模式动态扩展功能特性
装饰器模式是一种结构型设计模式,允许在不修改原有对象代码的前提下,动态地添加功能。它通过组合的方式,将功能封装在装饰器类中,实现灵活的功能扩展。
基本实现原理
核心思想是定义一个公共接口,基础组件和装饰器均实现该接口,装饰器持有组件的实例,从而在调用前后增强行为。
type Service interface {
Execute() string
}
type BasicService struct{}
func (b *BasicService) Execute() string {
return "执行基础服务"
}
type LoggingDecorator struct {
service Service
}
func (l *LoggingDecorator) Execute() string {
log.Println("开始执行")
result := l.service.Execute()
log.Println("执行完成")
return result
}
上述代码中,
LoggingDecorator 包装了
Service 实例,在保留原逻辑的同时增加了日志能力。通过链式包装,可叠加多个装饰器,如缓存、权限校验等。
优势与适用场景
- 避免类爆炸:相比继承,更轻量地组合功能
- 运行时动态扩展:可根据条件决定是否启用某项装饰
- 符合开闭原则:扩展开放,修改封闭
3.3 代理模式控制对象访问逻辑
代理模式通过引入中间层控制对目标对象的访问,适用于权限校验、延迟加载和日志记录等场景。
静态代理与动态代理对比
- 静态代理:在编译期确定代理类,职责单一但扩展性差
- 动态代理:运行时生成代理类,Java 中可通过
java.lang.reflect.Proxy 实现
Java 动态代理示例
public class AccessProxy implements InvocationHandler {
private Object target;
public AccessProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置权限检查");
Object result = method.invoke(target, args);
System.out.println("后置日志记录");
return result;
}
}
上述代码中,
invoke 方法拦截所有方法调用,实现访问控制。参数
proxy 为代理实例,
method 表示被调用的方法,
args 为方法参数。
第四章:行为型模式深度剖析
4.1 观察者模式实现事件驱动机制
观察者模式是事件驱动架构的核心设计模式之一,它定义了对象间一对多的依赖关系,当一个对象状态改变时,所有依赖者都会收到通知。
核心结构与角色
该模式包含两个主要角色:**主题(Subject)** 和 **观察者(Observer)**。主题维护观察者列表,并在状态变化时主动通知它们。
- Subject:管理观察者注册与通知
- Observer:定义接收更新的接口
Go语言实现示例
type Subject struct {
observers []func(string)
}
func (s *Subject) Attach(obs func(string)) {
s.observers = append(s.observers, obs)
}
func (s *Subject) Notify(msg string) {
for _, obs := range s.observers {
obs(msg)
}
}
上述代码中,
Attach 方法用于注册回调函数,
Notify 遍历所有观察者并传递事件消息,实现了松耦合的事件通信机制。
4.2 策略模式优化条件分支代码结构
在处理多重条件分支时,传统的
if-else 或
switch-case 结构容易导致代码臃肿、难以维护。策略模式通过将不同算法封装为独立类,实现行为的动态切换。
核心结构设计
定义统一接口,各类策略实现该接口:
public interface DiscountStrategy {
double calculate(double price);
}
public class NormalDiscount implements DiscountStrategy {
public double calculate(double price) {
return price * 0.9; // 9折
}
}
上述代码中,
DiscountStrategy 抽象出计算折扣的契约,各实现类封装具体逻辑。
上下文调用
使用上下文持有策略实例,运行时注入:
public class PricingContext {
private DiscountStrategy strategy;
public void setStrategy(DiscountStrategy strategy) {
this.strategy = strategy;
}
public double execute(double price) {
return strategy.calculate(price);
}
}
通过依赖注入方式解耦条件判断与执行逻辑,提升扩展性。新增策略无需修改原有代码,符合开闭原则。
4.3 迭代器模式封装集合遍历逻辑
在复杂集合结构中,直接暴露内部数据组织方式会导致耦合度上升。迭代器模式通过统一接口封装遍历逻辑,使客户端无需了解底层存储细节。
核心接口设计
type Iterator interface {
HasNext() bool
Next() interface{}
}
type Collection interface {
GetIterator() Iterator
}
上述接口分离了集合的访问与内部实现。HasNext 判断是否还有元素,Next 返回当前元素并移动指针。
典型应用场景
- 树形结构的深度优先遍历封装
- 数据库结果集的延迟加载处理
- 多数据源合并遍历的统一视图
通过注入不同迭代器实现,同一集合可支持顺序、逆序或过滤遍历,提升扩展性。
4.4 状态模式管理对象状态转换流
状态模式通过封装对象的状态行为,使对象在其内部状态改变时改变其行为,从而解耦状态判断与业务逻辑。
核心结构与角色
- Context:持有当前状态对象的实例;
- State 接口:定义状态行为契约;
- ConcreteState:实现特定状态下的行为。
代码示例
type State interface {
Handle(context *Context)
}
type ConcreteStateA struct{}
func (s *ConcreteStateA) Handle(context *Context) {
fmt.Println("State A handling")
context.SetState(&ConcreteStateB{})
}
上述代码中,
Handle 方法执行后自动切换状态,实现无缝流转。参数
context 允许状态修改上下文中的当前状态实例,驱动状态迁移。
状态转换表
| 当前状态 | 触发事件 | 下一状态 |
|---|
| A | Handle | B |
| B | Handle | A |
第五章:设计模式在现代前端架构中的演进与思考
随着前端工程化的发展,设计模式的应用已从传统的类继承模型转向更灵活的组合式架构。现代框架如 React 和 Vue 通过 Hooks 和 Composition API 推动了函数式模式的普及。
状态管理中的观察者模式演化
在 Redux 中,Store 的订阅机制是典型的观察者模式实现。通过
store.subscribe() 注册回调,组件可响应状态变化:
const store = createStore(rootReducer);
store.subscribe(() => {
console.log('State updated:', store.getState());
});
如今,React 的 Context 与 useReducer 结合,提供了更轻量的替代方案,减少了模板代码。
组合模式驱动 UI 构建
React 的组件模型本质上是组合模式的实践。通过嵌套组件构建可复用的 UI 树结构:
- Layout 组件封装通用布局逻辑
- Card 组件作为容器承载不同内容子组件
- HOC 或自定义 Hook 抽离交互行为
这种模式提升了 UI 的可维护性与扩展性。
依赖注入的函数式实现
传统 DI 模式在前端常被忽视,但通过工厂函数和配置对象可实现松耦合:
function createApiClient({ baseUrl, auth }) {
return {
get: (path) => fetch(`${baseUrl}${path}`, { headers: auth })
};
}
// 测试时可轻松替换 mock 实现
| 模式 | 适用场景 | 典型框架支持 |
|---|
| 观察者 | 状态更新通知 | Redux, RxJS |
| 组合 | UI 结构构建 | React, Vue |