第一章:JavaScript设计模式概述
JavaScript 设计模式是开发者在长期实践中总结出的可复用解决方案,用于应对常见的软件设计问题。它们并非具体的语法或 API,而是一种编程思想的体现,能够提升代码的可维护性、可扩展性和可读性。
设计模式的核心价值
- 提高代码复用性,减少重复逻辑
- 增强模块间的解耦,便于团队协作
- 提供标准化的结构,降低系统复杂度
常见的设计模式分类
| 类别 | 典型模式 | 用途说明 |
|---|
| 创建型 | 单例、工厂、构造器 | 控制对象的创建方式与时机 |
| 结构型 | 装饰器、适配器、代理 | 处理类与对象的组合关系 |
| 行为型 | 观察者、策略、命令 | 定义对象间通信与职责分配 |
一个简单的单例模式实现
// 确保一个类仅有一个实例,并提供全局访问点
class Singleton {
constructor() {
// 如果实例已存在,返回缓存实例
if (Singleton.instance) {
return Singleton.instance;
}
this.data = 'This is singleton data';
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[创建新实例并保存]
D --> C
第二章:创建型设计模式详解与应用
2.1 工厂模式:统一对象创建的优雅方案
工厂模式是一种创建型设计模式,旨在将对象的实例化过程封装起来,使客户端代码与具体类解耦。通过引入工厂角色,系统可以在不修改客户端逻辑的前提下灵活扩展新产品类型。
核心思想
工厂模式的核心在于定义一个用于创建对象的接口,但让子类决定实例化哪一个类。这遵循了“开闭原则”——对扩展开放,对修改封闭。
简单工厂示例(Go)
type Product interface {
GetName() string
}
type ConcreteProductA struct{}
func (p *ConcreteProductA) GetName() string { return "Product A" }
type ConcreteProductB struct{}
func (p *ConcreteProductB) GetName() string { return "Product B" }
type Factory struct{}
func (f *Factory) CreateProduct(typ string) Product {
switch typ {
case "A":
return &ConcreteProductA{}
case "B":
return &ConcreteProductB{}
default:
panic("unknown type")
}
}
上述代码中,
Factory 根据传入参数返回不同产品实例,调用方无需了解具体实现类的构造细节,仅依赖统一接口进行操作。
优势与适用场景
- 隔离对象创建与使用,提升模块可维护性
- 便于集中管理复杂创建逻辑,如配置驱动的对象生成
- 适用于需要动态选择实现类的场景,如插件体系、多支付网关等
2.2 单例模式:确保全局唯一实例的实践技巧
单例模式是一种创建型设计模式,确保一个类仅有一个实例,并提供全局访问点。在高并发场景下,需通过双重检查锁定保证线程安全。
懒汉式线程安全实现
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
使用
volatile 防止指令重排序,
synchronized 保证多线程环境下只创建一次实例。
应用场景与优劣分析
- 适用于日志对象、配置管理器等需唯一实例的场景
- 减少资源开销,避免重复创建对象
- 过度使用可能导致代码耦合度升高,不利于测试
2.3 建造者模式:复杂对象构建的分步封装
模式核心思想
建造者模式将复杂对象的构建过程分解为多个简单步骤,使同一构建过程可创建不同的表示。适用于具多个可选参数或配置的对象构造。
典型实现示例
public class Computer {
private String cpu;
private String ram;
private String storage;
private Computer(Builder builder) {
this.cpu = builder.cpu;
this.ram = builder.ram;
this.storage = builder.storage;
}
public static class Builder {
private String cpu;
private String ram;
private String storage;
public Builder setCpu(String cpu) {
this.cpu = cpu;
return this;
}
public Builder setRam(String ram) {
this.ram = ram;
return this;
}
public Computer build() {
return new Computer(this);
}
}
}
上述代码通过内部静态类
Builder 实现链式调用,逐步设置属性,最终调用
build() 生成不可变对象,有效避免构造函数爆炸问题。
使用场景对比
| 场景 | 适用模式 |
|---|
| 对象构造参数多且可选 | 建造者模式 |
| 对象创建需复用构建逻辑 | 建造者模式 |
2.4 原型模式:基于已有对象克隆的高效方式
原型模式是一种创建型设计模式,通过复制现有对象来避免复杂的构造过程。它适用于对象初始化成本较高的场景,能显著提升性能。
核心实现机制
在 Go 中,可通过接口定义克隆方法:
type Prototype interface {
Clone() Prototype
}
type ConcretePrototype struct {
Name string
Data map[string]interface{}
}
func (p *ConcretePrototype) Clone() Prototype {
// 深拷贝关键数据
data := make(map[string]interface{})
for k, v := range p.Data {
data[k] = v
}
return &ConcretePrototype{Name: p.Name, Data: data}
}
该实现中,
Clone() 方法返回一个新实例,确保原始对象与副本之间无引用共享,避免数据污染。
使用场景对比
| 场景 | 传统构造 | 原型模式 |
|---|
| 高频创建 | 耗时长 | 速度快 |
| 配置复杂对象 | 重复初始化 | 直接复制模板 |
2.5 抽象工厂模式:多类对象家族的协调创建
抽象工厂模式用于创建一系列相关或依赖对象的接口,而无需指定具体类。它适用于多个产品族共存的场景,保证同一工厂创建的产品属于同一“家族”。
核心结构与角色
- 抽象工厂(Abstract Factory):声明创建一组产品的方法
- 具体工厂(Concrete Factory):实现创建具体产品族的逻辑
- 抽象产品(Abstract Product):定义产品类型接口
- 具体产品(Concrete Product):实际被创建的对象
代码示例
type GUIFactory interface {
CreateButton() Button
CreateCheckbox() Checkbox
}
type WindowsFactory struct{}
func (f *WindowsFactory) CreateButton() Button {
return &WindowsButton{}
}
func (f *WindowsFactory) CreateCheckbox() Checkbox {
return &WindowsCheckbox{}
}
上述代码定义了一个跨平台 UI 控件创建工厂。
GUIFactory 接口统一了按钮和复选框的创建流程,
WindowsFactory 确保所有控件风格一致,实现界面元素的协调性。
第三章:结构型设计模式核心解析
3.1 适配器模式:不兼容接口之间的桥梁搭建
在软件开发中,不同系统或组件的接口往往存在不兼容问题。适配器模式通过封装一个类的接口,将其转换为客户期望的另一个接口,实现无缝协作。
典型应用场景
当遗留系统的数据服务接口与新模块定义的标准接口不一致时,适配器可作为中间层进行协议转换。
代码示例
// 目标接口
type Target interface {
Request() string
}
// 被适配者
type Adaptee struct{}
func (a *Adaptee) SpecificRequest() string {
return "特定请求"
}
// 适配器
type Adapter struct {
adaptee *Adaptee
}
func (a *Adapter) Request() string {
return a.adaptee.SpecificRequest()
}
上述代码中,
Adapter 包装了
Adaptee,将
SpecificRequest 转换为
Request,使原本不兼容的接口得以调用。
结构对比
| 角色 | 职责 |
|---|
| Target | 客户端期望的接口 |
| Adaptee | 现有需要适配的类 |
| Adapter | 协调两者,实现兼容 |
3.2 装饰器模式:动态扩展功能而不修改源码
装饰器模式是一种结构型设计模式,允许在不修改对象源码的前提下,动态地添加职责或功能。它通过组合的方式,将原始对象包裹在装饰器中,实现功能的叠加。
基本实现原理
以日志记录为例,使用装饰器增强函数行为:
package main
import (
"fmt"
"time"
)
type Service interface {
Execute()
}
type CoreService struct{}
func (s CoreService) Execute() {
fmt.Println("核心业务执行中...")
}
type LoggingDecorator struct {
service Service
}
func (d LoggingDecorator) Execute() {
fmt.Printf("开始执行 - 时间: %v\n", time.Now())
d.service.Execute()
fmt.Println("执行结束")
}
上述代码中,
LoggingDecorator 持有
Service 接口实例,可在调用前后插入日志逻辑,而无需改动
CoreService 的实现。
优势与应用场景
- 符合开闭原则:对扩展开放,对修改封闭
- 可组合多个装饰器,如日志、权限校验、缓存等
- 广泛应用于中间件、API 网关、I/O 流处理等场景
3.3 代理模式:控制对象访问的安全与性能优化
代理模式是一种结构型设计模式,通过引入代理对象控制对真实对象的访问,适用于安全校验、延迟加载和日志记录等场景。
静态代理与动态代理对比
- 静态代理:代理类在编译期确定,每个接口需编写独立代理类;
- 动态代理:运行时生成代理类,如 Java 的
Proxy 和 InvocationHandler。
Go 语言中的代理实现示例
type Service interface {
Request() string
}
type RealService struct{}
func (r *RealService) Request() string {
return "处理请求"
}
type Proxy struct {
real *RealService
}
func (p *Proxy) Request() string {
if p.real == nil {
p.real = &RealService{}
}
// 访问控制与日志
log.Println("请求前日志")
result := p.real.Request()
log.Println("请求完成")
return result
}
上述代码中,
Proxy 在调用真实服务前后插入日志逻辑,实现非侵入式增强。
第四章:行为型设计模式实战精讲
4.1 观察者模式:实现事件系统与数据驱动视图
观察者模式是一种行为设计模式,允许对象在状态变化时自动通知其依赖者。在前端框架中,该模式是实现数据响应式更新的核心机制。
核心结构
一个典型的观察者模式包含“主题(Subject)”和“观察者(Observer)”。当主题状态变更时,所有注册的观察者将被触发更新。
- Subject:管理观察者列表,提供订阅与通知接口
- Observer:实现更新方法,响应状态变化
简易实现示例
class Subject {
constructor() {
this.observers = [];
}
subscribe(observer) {
this.observers.push(observer);
}
notify(data) {
this.observers.forEach(observer => observer.update(data));
}
}
上述代码定义了一个可被监听的主题类。
subscribe 方法用于添加观察者,
notify 在数据变更时广播消息,触发各观察者的
update 方法,从而实现视图自动刷新。
4.2 策略模式:算法切换与业务规则解耦
策略模式是一种行为设计模式,它允许在运行时动态选择算法。通过将算法封装在独立的类中,客户端可以在不修改上下文逻辑的前提下切换具体实现。
核心结构与角色
- Strategy(策略接口):定义算法的公共操作;
- ConcreteStrategy(具体策略):实现不同版本的算法;
- Context(上下文):持有策略引用并委托执行。
代码示例
type PaymentStrategy interface {
Pay(amount float64) string
}
type CreditCardStrategy struct{}
func (c *CreditCardStrategy) Pay(amount float64) string {
return fmt.Sprintf("Paid %.2f via Credit Card", amount)
}
type PayPalStrategy struct{}
func (p *PayPalStrategy) Pay(amount float64) string {
return fmt.Sprintf("Paid %.2f via PayPal", amount)
}
type ShoppingCart struct {
strategy PaymentStrategy
}
func (s *ShoppingCart) SetStrategy(strategy PaymentStrategy) {
s.strategy = strategy
}
func (s *ShoppingCart) Checkout(amount float64) string {
return s.strategy.Pay(amount)
}
上述代码中,
PaymentStrategy 定义了统一支付接口,两种具体策略分别实现不同支付方式。
ShoppingCart 通过设置不同策略实例,在运行时灵活切换支付逻辑,实现业务规则与核心流程的解耦。
4.3 命令模式:将请求封装为可管理的对象
命令模式是一种行为设计模式,它将请求封装为独立对象,使你可以用不同的请求、队列或日志来参数化其他对象。
核心结构
命令模式包含四个关键角色:
- 命令(Command):定义执行操作的接口
- 具体命令(Concrete Command):实现命令接口,绑定接收者和动作
- 接收者(Receiver):执行请求的实际逻辑
- 调用者(Invoker):触发命令执行,不关心具体实现
代码示例
type Command interface {
Execute()
}
type LightOnCommand struct {
light *Light
}
func (c *LightOnCommand) Execute() {
c.light.TurnOn()
}
上述代码定义了一个打开灯的具体命令。LightOnCommand 持有 Light 接收者实例,并在 Execute 中调用其 TurnOn 方法,实现了请求与执行的解耦。
4.4 状态模式:状态驱动的行为自动切换机制
状态模式是一种行为设计模式,允许对象在内部状态改变时改变其行为。通过将状态相关逻辑封装到独立的类中,避免了冗长的条件判断语句。
核心结构与实现
状态模式包含上下文(Context)和具体状态类。上下文持有当前状态对象,所有状态相关的操作都委托给当前状态实例。
type State interface {
Handle(context *Context)
}
type Context struct {
currentState State
}
func (c *Context) Request() {
c.currentState.Handle(c)
}
上述代码定义了状态接口与上下文。当请求触发时,行为由当前状态对象决定,实现动态切换。
应用场景
- 订单生命周期管理(待支付、已发货、已完成)
- 游戏角色状态控制(奔跑、跳跃、死亡)
- 有限状态机建模
第五章:设计模式的综合应用与未来趋势
微服务架构中的模式融合
在现代微服务系统中,策略模式与工厂模式常被结合使用,以实现动态服务路由。例如,在支付网关选择场景中,可根据用户地理位置自动实例化对应的支付处理器。
- 策略模式定义统一接口,封装不同算法(如支付宝、PayPal)
- 工厂模式负责根据运行时条件创建具体策略实例
- 结合依赖注入,提升测试性与模块解耦
type PaymentStrategy interface {
Process(amount float64) error
}
type PaymentFactory struct{}
func (f *PaymentFactory) GetStrategy(region string) PaymentStrategy {
switch region {
case "CN":
return &Alipay{}
case "US":
return &PayPal{}
default:
return &DefaultGateway{}
}
}
云原生环境下的演进方向
随着 Kubernetes 和服务网格的普及,观察者模式被广泛用于事件驱动架构中。Pod 状态变更触发监控组件更新,实现弹性伸缩决策。
| 设计模式 | 应用场景 | 技术实现 |
|---|
| 装饰器模式 | 日志/监控增强 | Go Middleware 链 |
| 命令模式 | 运维操作队列 | K8s Operator 模式 |
图:基于事件总线的观察者集群
[Event Producer] → [Message Broker] → {Observer A, Observer B, Scaling Engine}
函数式编程的兴起推动了责任链模式的简化实现,通过高阶函数组合替代传统对象链。在 API 网关中,认证、限流、审计等中间件可声明式串联。