23个JavaScript设计模式实战

张玥 2025年7月31日 阅读时间 70分钟
JavaScript 设计模式 面向对象 代码优化 架构设计
JavaScript设计模式实战

设计模式是软件开发中解决特定问题的可复用方案。在JavaScript中,合理运用设计模式可以提升代码的可维护性、可扩展性和可复用性。 本文介绍了23种常用的JavaScript设计模式,每种模式都包含实际应用场景、代码实现和可视化示例。 无论你是初学者还是经验丰富的开发者,这些设计模式都将帮助你构建更健壮、更灵活的应用程序。

1. 单例模式 (Singleton)

确保一个类只有一个实例,并提供全局访问点。常用于全局状态管理、日志记录器等场景。

// 单例模式实现
class Logger {
  constructor() {
    if (!Logger.instance) {
      this.logs = [];
      Logger.instance = this;
    }
    return Logger.instance;
  }

  log(message) {
    this.logs.push(message);
    console.log(`LOG: ${message}`);
  }
}

// 使用示例
const logger1 = new Logger();
const logger2 = new Logger();
console.log(logger1 === logger2); // true

单例实例

全局共享唯一实例

尝试多次创建实例,返回的都是同一个对象

2. 工厂模式 (Factory)

创建对象而不指定具体类。封装实例化逻辑,使代码更灵活、可扩展。

// 工厂模式实现
class Car {
  constructor(options) {
    this.type = options.type || 'sedan';
    this.color = options.color || 'white';
  }
}

class Truck {
  constructor(options) {
    this.type = options.type || 'truck';
    this.color = options.color || 'blue';
    this.capacity = options.capacity || '5t';
  }
}

class VehicleFactory {
  createVehicle(options) {
    switch(options.vehicleType) {
      case 'car':
        return new Car(options);
      case 'truck':
        return new Truck(options);
    }
  }
}

// 使用示例
const factory = new VehicleFactory();
const myCar = factory.createVehicle({
  vehicleType: 'car',
  color: 'red'
});

工厂方法

创建车辆实例

Car
Truck

3. 观察者模式 (Observer)

定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都会得到通知。

// 观察者模式实现
class Subject {
  constructor() {
    this.observers = [];
  }

  addObserver(observer) {
    this.observers.push(observer);
  }

  removeObserver(observer) {
    this.observers = this.observers.filter(obs => obs !== observer);
  }

  notify(data) {
    this.observers.forEach(observer => observer.update(data));
  }
}

class Observer {
  update(data) {
    console.log(`收到更新: ${data}`);
  }
}

// 使用示例
const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();

subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notify('状态更新!');

主题 (Subject)

观察者 1

观察者 2

观察者 3

4. 策略模式 (Strategy)

定义一系列算法,封装每个算法,并使它们可以互换。让算法的变化独立于使用它的客户端。

// 策略模式实现
class Shipping {
  constructor() {
    this.strategy = null;
  }

  setStrategy(strategy) {
    this.strategy = strategy;
  }

  calculate(parcel) {
    return this.strategy.calculate(parcel);
  }
}

class Fedex {
  calculate(parcel) {
    // Fedex 计算逻辑
    return parcel.weight * 3.5;
  }
}

class UPS {
  calculate(parcel) {
    // UPS 计算逻辑
    return parcel.weight * 2.8;
  }
}

// 使用示例
const parcel = { weight: 5 };
const shipping = new Shipping();

shipping.setStrategy(new Fedex());
console.log(`Fedex 费用: ${shipping.calculate(parcel)}`);

shipping.setStrategy(new UPS());
console.log(`UPS 费用: ${shipping.calculate(parcel)}`);

物流计算器

动态切换策略

Fedex
UPS
DHL

5. 装饰器模式 (Decorator)

动态地给一个对象添加一些额外的职责,相比继承更加灵活。

// 装饰器模式实现
class Coffee {
  cost() {
    return 5;
  }
}

class MilkDecorator {
  constructor(coffee) {
    this.coffee = coffee;
  }

  cost() {
    return this.coffee.cost() + 2;
  }
}

class SugarDecorator {
  constructor(coffee) {
    this.coffee = coffee;
  }

  cost() {
    return this.coffee.cost() + 1;
  }
}

// 使用示例
let coffee = new Coffee();
coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);
console.log(`咖啡总价: ${coffee.cost()}元`);
基础咖啡
+
牛奶
+

装饰后咖啡

总价: 8元

6. 适配器模式 (Adapter)

将一个类的接口转换成客户希望的另一个接口,使原本不兼容的类可以一起工作。

// 适配器模式实现 class OldCalculator { operations(a, b, operation) { switch(operation) { case 'add': return a + b; case 'sub': return a - b; } } } class NewCalculator { add(a, b) { return a + b; } sub(a, b) { return a - b; } } class CalculatorAdapter { constructor() { this.calculator = new NewCalculator(); } operations(a, b, operation) { switch(operation) { case 'add': return this.calculator.add(a, b); case 'sub': return this.calculator.sub(a, b); } } } // 使用示例 const oldCalc = new OldCalculator(); const adapter = new CalculatorAdapter(); console.log(oldCalc.operations(5, 3, 'add')); // 8 console.log(adapter.operations(5, 3, 'add')); // 8

适配器

转换接口格式

旧接口
新接口

7. 外观模式 (Facade)

为子系统中的一组接口提供一个统一的高层接口,使子系统更容易使用。

// 外观模式实现 class CPU { start() { console.log('CPU启动'); } shutdown() { console.log('CPU关闭'); } } class Memory { load() { console.log('内存加载'); } clear() { console.log('内存清理'); } } class ComputerFacade { constructor() { this.cpu = new CPU(); this.memory = new Memory(); } start() { this.cpu.start(); this.memory.load(); console.log('电脑启动完成'); } shutdown() { this.memory.clear(); this.cpu.shutdown(); console.log('电脑关闭完成'); } } // 使用示例 const computer = new ComputerFacade(); computer.start(); computer.shutdown();

电脑外观

简化复杂操作

CPU
内存
硬盘

8. 代理模式 (Proxy)

为其他对象提供一种代理以控制对这个对象的访问。

// 代理模式实现 class RealImage { constructor(filename) { this.filename = filename; this.loadFromDisk(); } display() { console.log(`显示图片: ${this.filename}`); } loadFromDisk() { console.log(`从磁盘加载: ${this.filename}`); } } class ProxyImage { constructor(filename) { this.filename = filename; this.realImage = null; } display() { if (!this.realImage) { this.realImage = new RealImage(this.filename); } this.realImage.display(); } } // 使用示例 const image = new ProxyImage('test.jpg'); image.display(); // 第一次会加载 image.display(); // 直接显示

图片代理

延迟加载控制

客户端
真实图片

9. 组合模式 (Composite)

将对象组合成树形结构以表示"部分-整体"的层次结构,使客户对单个对象和复合对象的使用具有一致性。

// 组合模式实现 class Employee { constructor(name, position) { this.name = name; this.position = position; this.subordinates = []; } add(employee) { this.subordinates.push(employee); } remove(employee) { const index = this.subordinates.indexOf(employee); if (index !== -1) { this.subordinates.splice(index, 1); } } getSubordinates() { return this.subordinates; } toString() { return `${this.name} - ${this.position}`; } } // 使用示例 const ceo = new Employee('张三', 'CEO'); const headSales = new Employee('李四', '销售主管'); const headMarketing = new Employee('王五', '市场主管'); ceo.add(headSales); ceo.add(headMarketing); const sales1 = new Employee('赵六', '销售员'); const sales2 = new Employee('钱七', '销售员'); headSales.add(sales1); headSales.add(sales2); console.log(ceo.toString()); ceo.getSubordinates().forEach(emp => { console.log(` ${emp.toString()}`); emp.getSubordinates().forEach(sub => console.log(` ${sub.toString()}`)); });

组织结构

树形结构管理

CEO
- 销售主管
-- 销售员1
-- 销售员2
- 市场主管

10. 享元模式 (Flyweight)

运用共享技术有效地支持大量细粒度的对象。

// 享元模式实现 class Car { constructor(model, color) { this.model = model; this.color = color; } } class CarFactory { constructor() { this.cars = {}; } create(model, color) { const key = `${model}_${color}`; if (!this.cars[key]) { this.cars[key] = new Car(model, color); } return this.cars[key]; } getCount() { return Object.keys(this.cars).length; } } // 使用示例 const factory = new CarFactory(); const cars = [ factory.create('BMW', 'red'), factory.create('Audi', 'blue'), factory.create('BMW', 'red'), // 重复使用 factory.create('BMW', 'blue') ]; console.log(`总创建数: ${cars.length}`); console.log(`实际对象数: ${factory.getCount()}`);

汽车工厂

共享相同属性

BMW-red
Audi-blue
BMW-blue

11. 责任链模式 (Chain of Responsibility)

将请求的发送者和接收者解耦,使多个对象都有机会处理这个请求。

// 责任链模式实现 class Handler { constructor() { this.nextHandler = null; } setNext(handler) { this.nextHandler = handler; return handler; } handle(request) { if (this.nextHandler) { return this.nextHandler.handle(request); } return null; } } class Manager extends Handler { handle(request) { if (request.amount <= 1000) { return `经理批准了${request.amount}元的请求`; } return super.handle(request); } } class Director extends Handler { handle(request) { if (request.amount <= 5000) { return `总监批准了${request.amount}元的请求`; } return super.handle(request); } } class CEO extends Handler { handle(request) { if (request.amount <= 10000) { return `CEO批准了${request.amount}元的请求`; } return `需要董事会讨论${request.amount}元的请求`; } } // 使用示例 const manager = new Manager(); const director = new Director(); const ceo = new CEO(); manager.setNext(director).setNext(ceo); console.log(manager.handle({ amount: 800 })); // 经理 console.log(manager.handle({ amount: 3000 })); // 总监 console.log(manager.handle({ amount: 8000 })); // CEO console.log(manager.handle({ amount: 20000 }));// 董事会

审批链条

依次传递请求

经理 ≤1000
总监 ≤5000
CEO ≤10000

12. 命令模式 (Command)

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化。

// 命令模式实现 class Light { on() { console.log('灯打开了'); } off() { console.log('灯关闭了'); } } class Command { execute() {} undo() {} } class LightOnCommand extends Command { constructor(light) { super(); this.light = light; } execute() { this.light.on(); } undo() { this.light.off(); } } class LightOffCommand extends Command { constructor(light) { super(); this.light = light; } execute() { this.light.off(); } undo() { this.light.on(); } } class RemoteControl { constructor() { this.commands = []; this.history = []; } setCommand(command) { this.commands.push(command); } pressButton(index) { if (index < this.commands.length) { const cmd = this.commands[index]; cmd.execute(); this.history.push(cmd); } } undo() { if (this.history.length > 0) { const cmd = this.history.pop(); cmd.undo(); } } } // 使用示例 const light = new Light(); const remote = new RemoteControl(); remote.setCommand(new LightOnCommand(light)); remote.setCommand(new LightOffCommand(light)); remote.pressButton(0); // 开灯 remote.pressButton(1); // 关灯 remote.undo(); // 撤销最后操作

遥控器

封装操作为对象

开灯命令
关灯命令

13. 迭代器模式 (Iterator)

提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。

// 迭代器模式实现 class Collection { constructor() { this.items = []; } addItem(item) { this.items.push(item); } getIterator() { return new Iterator(this); } } class Iterator { constructor(collection) { this.collection = collection; this.index = 0; } next() { return this.collection.items[this.index++]; } hasNext() { return this.index < this.collection.items.length; } reset() { this.index = 0; } } // 使用示例 const collection = new Collection(); collection.addItem('Item 1'); collection.addItem('Item 2'); collection.addItem('Item 3'); const iterator = collection.getIterator(); while(iterator.hasNext()) { console.log(iterator.next()); } // 重置迭代器 iterator.reset(); console.log('再次遍历:'); while(iterator.hasNext()) { console.log(iterator.next()); }

集合迭代器

顺序访问元素

Item 1
Item 2
Item 3

14. 备忘录模式 (Memento)

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。

// 备忘录模式实现 class Editor { constructor() { this.content = ''; } type(words) { this.content += words; } save() { return new EditorMemento(this.content); } restore(memento) { this.content = memento.getContent(); } getContent() { return this.content; } } class EditorMemento { constructor(content) { this.content = content; } getContent() { return this.content; } } // 使用示例 const editor = new Editor(); editor.type('第一段文字。'); const saved = editor.save(); editor.type('第二段文字。'); console.log(editor.getContent()); // 当前内容 editor.restore(saved); console.log(editor.getContent()); // 恢复到保存点

编辑器状态

保存与恢复

当前状态
备忘录状态

15. 状态模式 (State)

允许一个对象在其内部状态改变时改变它的行为。

// 状态模式实现 class TrafficLight { constructor() { this.states = [new RedLight(), new YellowLight(), new GreenLight()]; this.current = this.states[0]; } change() { const totalStates = this.states.length; let currentIndex = this.states.indexOf(this.current); this.current = this.states[(currentIndex + 1) % totalStates]; } sign() { return this.current.sign(); } } class Light { constructor(light) { this.light = light; } } class RedLight extends Light { constructor() { super('red'); } sign() { return 'STOP'; } } class YellowLight extends Light { constructor() { super('yellow'); } sign() { return 'READY'; } } class GreenLight extends Light { constructor() { super('green'); } sign() { return 'GO'; } } // 使用示例 const trafficLight = new TrafficLight(); console.log(trafficLight.sign()); // STOP trafficLight.change(); console.log(trafficLight.sign()); // READY trafficLight.change(); console.log(trafficLight.sign()); // GO

交通灯

状态转换

红灯
黄灯
绿灯

16. 访问者模式 (Visitor)

表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

// 访问者模式实现 class Employee { constructor(name, salary) { this.name = name; this.salary = salary; } accept(visitor) { visitor.visit(this); } } class Department { constructor() { this.employees = []; } addEmployee(employee) { this.employees.push(employee); } accept(visitor) { this.employees.forEach(emp => emp.accept(visitor)); } } class SalaryVisitor { visit(employee) { employee.salary = Math.floor(employee.salary * 1.1); console.log(`${employee.name}的新工资: ${employee.salary}`); } } // 使用示例 const dept = new Department(); dept.addEmployee(new Employee('张三', 10000)); dept.addEmployee(new Employee('李四', 15000)); const salaryVisitor = new SalaryVisitor(); dept.accept(salaryVisitor);

员工部门

访问操作

员工1
员工2
员工3

17. 桥接模式 (Bridge)

将抽象部分与它的实现部分分离,使它们都可以独立地变化。

// 桥接模式实现 class Printer { constructor(ink) { this.ink = ink; } } class EpsonPrinter extends Printer { print() { return `Epson打印机使用 ${this.ink.get()} 墨水`; } } class HPPrinter extends Printer { print() { return `HP打印机使用 ${this.ink.get()} 墨水`; } } class Ink { get() {} } class BlackInk extends Ink { get() { return '黑色'; } } class ColorInk extends Ink { get() { return '彩色'; } } // 使用示例 const blackInk = new BlackInk(); const colorInk = new ColorInk(); const epsonPrinter = new EpsonPrinter(blackInk); const hpPrinter = new HPPrinter(colorInk); console.log(epsonPrinter.print()); console.log(hpPrinter.print());

打印机系统

抽象与实现分离

打印机
墨水

18. 建造者模式 (Builder)

将一个复杂对象的构建与它的表示分离,使同样的构建过程可以创建不同的表示。

// 建造者模式实现 class Pizza { constructor() { this.toppings = []; this.crust = '常规'; this.sauce = '番茄'; } addTopping(topping) { this.toppings.push(topping); return this; } setCrust(crust) { this.crust = crust; return this; } setSauce(sauce) { this.sauce = sauce; return this; } describe() { return `一个${this.crust}饼底,${this.sauce}酱料的比萨,配料有:${this.toppings.join(', ')}`; } } class PizzaBuilder { constructor() { this.pizza = new Pizza(); } addPepperoni() { this.pizza.addTopping('意大利辣香肠'); return this; } addMushrooms() { this.pizza.addTopping('蘑菇'); return this; } setThinCrust() { this.pizza.setCrust('薄'); return this; } setBBQSauce() { this.pizza.setSauce('烧烤'); return this; } build() { return this.pizza; } } // 使用示例 const builder = new PizzaBuilder(); const pizza = builder.addPepperoni() .addMushrooms() .setThinCrust() .setBBQSauce() .build(); console.log(pizza.describe());

比萨建造者

分步构建

饼底
酱料
配料

19. 原型模式 (Prototype)

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

// 原型模式实现 class Car { constructor(name, model) { this.name = name; this.model = model; } clone() { return new Car(this.name, this.model); } } // 使用示例 const prototypeCar = new Car('Tesla', 'Model S'); const car1 = prototypeCar.clone(); const car2 = prototypeCar.clone(); car1.model = 'Model 3'; console.log(car1); // Tesla Model 3 console.log(car2); // Tesla Model S

汽车原型

克隆实例

原型
克隆1
克隆2

20. 中介者模式 (Mediator)

用一个中介对象来封装一系列的对象交互,使各对象不需要显式地相互引用。

// 中介者模式实现 class ChatRoom { showMessage(user, message) { const time = new Date().toLocaleTimeString(); console.log(`${time} [${user.getName()}]: ${message}`); } } class User { constructor(name, chatMediator) { this.name = name; this.chatMediator = chatMediator; } getName() { return this.name; } send(message) { this.chatMediator.showMessage(this, message); } } // 使用示例 const chatroom = new ChatRoom(); const john = new User('John', chatroom); const jane = new User('Jane', chatroom); john.send('Hi there!'); jane.send('Hey!');

聊天室

中介通信

用户1
用户2

21. 模板方法模式 (Template Method)

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。

// 模板方法模式实现 class DataProcessor { process() { this.loadData(); this.validateData(); this.analyzeData(); this.reportResults(); } loadData() { throw new Error('必须实现loadData方法'); } validateData() { console.log('默认数据验证逻辑'); } analyzeData() { throw new Error('必须实现analyzeData方法'); } reportResults() { console.log('生成报告...'); } } class SalesDataProcessor extends DataProcessor { loadData() { console.log('加载销售数据...'); } analyzeData() { console.log('分析销售趋势...'); } } // 使用示例 const processor = new SalesDataProcessor(); processor.process();

数据处理流程

固定算法骨架

加载数据
验证数据
分析数据

22. 解释器模式 (Interpreter)

给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

// 解释器模式实现 class Context { constructor(input) { this.input = input; this.output = 0; } } class Expression { interpret(context) { if (context.input.startsWith(this.nine())) { context.output += 9 * this.multiplier(); context.input = context.input.substring(2); } else if (context.input.startsWith(this.four())) { context.output += 4 * this.multiplier(); context.input = context.input.substring(2); } else if (context.input.startsWith(this.five())) { context.output += 5 * this.multiplier(); context.input = context.input.substring(1); } while (context.input.startsWith(this.one())) { context.output += 1 * this.multiplier(); context.input = context.input.substring(1); } } one() { return ''; } four() { return ''; } five() { return ''; } nine() { return ''; } multiplier() { return 0; } } class ThousandExpression extends Expression { one() { return 'M'; } four() { return ' '; } five() { return ' '; } nine() { return ' '; } multiplier() { return 1000; } } // 使用示例 const roman = "MCMXXVIII"; const context = new Context(roman); const tree = [new ThousandExpression()]; tree.forEach(exp => exp.interpret(context)); console.log(`${roman} = ${context.output}`);

罗马数字解释器

解析特定语法

输入: MCMXXVIII
输出: 1928

23. 空对象模式 (Null Object)

提供一个对象作为缺少给定类型对象的替代品,该对象不做任何动作。

// 空对象模式实现 class User { constructor(id, name) { this.id = id; this.name = name; } hasAccess() { return true; } } class NullUser { constructor() { this.id = -1; this.name = 'Guest'; } hasAccess() { return false; } } const users = [ new User(1, 'Alice'), new User(2, 'Bob') ]; function getUser(id) { const user = users.find(u => u.id === id); return user || new NullUser(); } // 使用示例 console.log(getUser(1).name); // Alice console.log(getUser(3).name); // Guest console.log(getUser(3).hasAccess()); // false

空用户对象

替代null值

真实用户
空用户