JavaScript 设计模式终极指南:从入门到精通
还在为复杂的代码架构而头疼?掌握这23种设计模式,让你的JavaScript代码质量提升一个维度!
🎯 读完本文你将获得
- 23种核心设计模式的深度解析
- 每种模式的真实应用场景和代码示例
- 模式选择的最佳实践和注意事项
- 避免常见陷阱的专业建议
- 提升代码可维护性和扩展性的实战技巧
📊 设计模式分类总览
🏗️ 创建型模式 (Creational Patterns)
🏭 工厂模式 (Factory Pattern)
现实场景:想象你在建房子需要门,你不会每次都亲自制作,而是从工厂购买。
核心思想:将对象创建逻辑封装起来,客户端无需知道具体实现细节。
// 门接口
class WoodenDoor {
constructor(width, height) {
this.width = width;
this.height = height;
}
getWidth() { return this.width; }
getHeight() { return this.height; }
}
// 工厂
const DoorFactory = {
makeDoor: (width, height) => new WoodenDoor(width, height)
};
// 使用
const door = DoorFactory.makeDoor(100, 200);
console.log('Width:', door.getWidth()); // 100
console.log('Height:', door.getHeight()); // 200
适用场景:当对象创建逻辑复杂或需要统一管理时。
🔨 抽象工厂 (Abstract Factory)
现实场景:木门需要木匠,铁门需要焊工,不同材质的门需要对应的专家。
核心思想:创建相关或依赖对象的家族,而无需指定具体类。
// 抽象产品族
class WoodenDoor {
getDescription() { console.log('I am a wooden door'); }
}
class IronDoor {
getDescription() { console.log('I am an iron door'); }
}
class Carpenter {
getDescription() { console.log('I can only fit wooden doors'); }
}
class Welder {
getDescription() { console.log('I can only fit iron doors'); }
}
// 抽象工厂
class WoodenDoorFactory {
makeDoor() { return new WoodenDoor(); }
makeFittingExpert() { return new Carpenter(); }
}
class IronDoorFactory {
makeDoor() { return new IronDoor(); }
makeFittingExpert() { return new Welder(); }
}
👷 建造者模式 (Builder Pattern)
解决痛点:避免构造器参数爆炸(Telescoping Constructor Anti-Pattern)
class Burger {
constructor(builder) {
this.size = builder.size;
this.cheese = builder.cheese || false;
this.pepperoni = builder.pepperoni || false;
this.lettuce = builder.lettuce || false;
this.tomato = builder.tomato || false;
}
}
class BurgerBuilder {
constructor(size) { this.size = size; }
addCheese() { this.cheese = true; return this; }
addPepperoni() { this.pepperoni = true; return this; }
addLettuce() { this.lettuce = true; return this; }
addTomato() { this.tomato = true; return this; }
build() { return new Burger(this); }
}
// 链式调用
const burger = new BurgerBuilder(14)
.addPepperoni()
.addLettuce()
.addTomato()
.build();
🐑 原型模式 (Prototype Pattern)
JavaScript特色:利用原生原型机制实现对象克隆
class Sheep {
constructor(name, category = "Mountain Sheep") {
this.name = name;
this.category = category;
}
setName(name) { this.name = name; }
getName() { return this.name; }
}
// 使用JavaScript内置原型
const original = new Sheep("Jolly");
const cloned = Object.create(Object.getPrototypeOf(original));
Object.assign(cloned, original);
cloned.setName("Dolly");
console.log(original.getName()); // Jolly
console.log(cloned.getName()); // Dolly
💍 单例模式 (Singleton Pattern)
注意事项:单例模式被认为是反模式,应谨慎使用
const Leader = (function() {
let instance;
function createInstance() {
const privateInfo = 'Super private';
const name = 'Leader Name';
return {
getName: () => name,
getPrivateInfo: () => privateInfo
};
}
return {
getInstance: function() {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
const leader1 = Leader.getInstance();
const leader2 = Leader.getInstance();
console.log(leader1 === leader2); // true
🧱 结构型模式 (Structural Patterns)
🔌 适配器模式 (Adapter Pattern)
现实场景:不同类型的充电器转换头
// 目标接口
class Lion {
roar() {}
}
// 需要适配的类
class WildDog {
bark() { console.log('Bark!'); }
}
// 适配器
class WildDogAdapter extends Lion {
constructor(dog) {
super();
this.dog = dog;
}
roar() { this.dog.bark(); }
}
// 使用
const dog = new WildDog();
const adaptedDog = new WildDogAdapter(dog);
adaptedDog.roar(); // Bark!
🚡 桥接模式 (Bridge Pattern)
核心思想:抽象与实现分离,支持多维度变化
// 实现层次
class Theme {
getColor() {}
}
class DarkTheme extends Theme {
getColor() { return 'Dark Black'; }
}
class LightTheme extends Theme {
getColor() { return 'Off White'; }
}
// 抽象层次
class WebPage {
constructor(theme) { this.theme = theme; }
getContent() {}
}
class AboutPage extends WebPage {
getContent() { return `About page in ${this.theme.getColor()}`; }
}
class CareersPage extends WebPage {
getContent() { return `Careers page in ${this.theme.getColor()}`; }
}
🌿 组合模式 (Composite Pattern)
适用场景:处理树形结构数据,统一对待单个对象和组合对象
class Employee {
constructor(name, salary) {
this.name = name;
this.salary = salary;
}
getName() { return this.name; }
getSalary() { return this.salary; }
getRoles() { return this.roles; }
}
class Organization {
constructor() { this.employees = []; }
addEmployee(employee) { this.employees.push(employee); }
getNetSalaries() {
return this.employees.reduce((total, emp) => total + emp.getSalary(), 0);
}
}
// 使用
const org = new Organization();
org.addEmployee(new Employee('John', 10000));
org.addEmployee(new Employee('Jane', 12000));
console.log(org.getNetSalaries()); // 22000
☕ 装饰器模式 (Decorator Pattern)
JavaScript实现:利用高阶函数和类继承
class Coffee {
getCost() { return 10; }
getDescription() { return 'Simple coffee'; }
}
// 装饰器基类
class CoffeeDecorator {
constructor(coffee) { this.coffee = coffee; }
getCost() { return this.coffee.getCost(); }
getDescription() { return this.coffee.getDescription(); }
}
class MilkDecorator extends CoffeeDecorator {
getCost() { return super.getCost() + 2; }
getDescription() { return super.getDescription() + ', milk'; }
}
class WhipDecorator extends CoffeeDecorator {
getCost() { return super.getCost() + 5; }
getDescription() { return super.getDescription() + ', whip'; }
}
// 使用
let coffee = new Coffee();
coffee = new MilkDecorator(coffee);
coffee = new WhipDecorator(coffee);
console.log(coffee.getCost()); // 17
console.log(coffee.getDescription()); // Simple coffee, milk, whip
📦 外观模式 (Facade Pattern)
现实场景:电脑开机按钮背后复杂的启动流程
class Computer {
getElectricShock() { console.log('Ouch!'); }
makeSound() { console.log('Beep beep!'); }
showLoadingScreen() { console.log('Loading..'); }
bam() { console.log('Ready!'); }
closeEverything() { console.log('Closing..'); }
sooth() { console.log('Zzzzz'); }
}
class ComputerFacade {
constructor(computer) { this.computer = computer; }
turnOn() {
this.computer.getElectricShock();
this.computer.makeSound();
this.computer.showLoadingScreen();
this.computer.bam();
}
turnOff() {
this.computer.closeEverything();
this.computer.sooth();
}
}
// 简化接口
const computer = new ComputerFacade(new Computer());
computer.turnOn(); // 复杂的启动过程
computer.turnOff(); // 复杂的关闭过程
🔄 行为型模式 (Behavioral Patterns)
👀 观察者模式 (Observer Pattern)
现代JavaScript实现:使用Proxy和Set
class Observable {
constructor() {
this.observers = new Set();
}
subscribe(observer) {
this.observers.add(observer);
return () => this.observers.delete(observer);
}
notify(data) {
this.observers.forEach(observer => observer(data));
}
}
// 使用
const observable = new Observable();
const unsubscribe = observable.subscribe(data => {
console.log('Observer 1:', data);
});
observable.subscribe(data => {
console.log('Observer 2:', data);
});
observable.notify('Hello World!');
// Observer 1: Hello World!
// Observer 2: Hello World!
unsubscribe();
observable.notify('After unsubscribe');
// Observer 2: After unsubscribe
🎯 策略模式 (Strategy Pattern)
适用场景:多种算法或策略,客户端可动态选择
class PaymentStrategy {
pay(amount) {}
}
class CreditCardStrategy extends PaymentStrategy {
pay(amount) {
console.log(`Paid ${amount} using Credit Card`);
}
}
class PayPalStrategy extends PaymentStrategy {
pay(amount) {
console.log(`Paid ${amount} using PayPal`);
}
}
class ShoppingCart {
constructor() {
this.amount = 0;
this.strategy = null;
}
setPaymentStrategy(strategy) {
this.strategy = strategy;
}
checkout() {
if (this.strategy) {
this.strategy.pay(this.amount);
} else {
console.log('No payment strategy set');
}
}
}
📈 设计模式选择指南
| 问题场景 | 推荐模式 | 优点 |
|---|---|---|
| 对象创建复杂 | 工厂模式/建造者 | 封装创建逻辑,降低耦合 |
| 需要家族相关对象 | 抽象工厂 | 确保对象兼容性 |
| 对象开销大 | 原型模式 | 通过克隆减少开销 |
| 接口不兼容 | 适配器模式 | 使不兼容接口协同工作 |
| 抽象与实现分离 | 桥接模式 | 支持多维度变化 |
| 树形结构处理 | 组合模式 | 统一对待个体和组合 |
| 动态添加功能 | 装饰器模式 | 遵循开闭原则 |
| 复杂子系统 | 外观模式 | 提供简化接口 |
| 对象状态变化 | 状态模式 | 封装状态相关行为 |
| 多种算法选择 | 策略模式 | 灵活切换算法 |
🚀 最佳实践与注意事项
✅ 该做的
- 适时使用模式:只在真正需要时引入设计模式
- 保持简单:优先选择简单解决方案
- 遵循SOLID原则:确保模式应用符合设计原则
- 考虑JavaScript特性:利用语言特性简化模式实现
❌ 不该做的
- 过度设计:不要为了模式而模式
- 忽视性能:某些模式可能带来性能开销
- 违反YAGNI:不要提前实现可能不需要的功能
- 忽略可读性:模式应该提高代码可读性,而不是降低
🎓 学习路径建议
📝 总结
设计模式是解决特定问题的经验总结,但不是银弹。在JavaScript中应用设计模式时:
- 理解问题本质:确保模式真正解决你的问题
- 利用语言特性:JavaScript的动态特性可以简化某些模式
- 保持代码简洁:避免过度工程化
- 注重可维护性:模式应该让代码更易理解和维护
记住:最好的模式是适合当前场景的模式。不要生搬硬套,而是根据具体需求灵活选择和调整。
掌握设计模式就像获得了一套强大的工具箱,但真正的艺术在于知道何时使用哪件工具。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



