
JavaScript 设计模式是在软件开发中针对常见问题的可复用解决方案。由于 JavaScript 是动态、原型继承、支持函数式与面向对象的多范式语言,许多传统设计模式在 JavaScript 中既有经典实现,也有更简洁的现代实现。
1. 设计模式分类
通常参考 GoF(Gang of Four)的 23 种设计模式,分为三大类:
1)创建型:对象创建机制
2)结构型:对象组合与类之间的关系
3)行为型:对象之间的职责分配与通信
在 JavaScript 中,由于函数是一等公民、闭包、原型链等特性,有些模式实现更为灵活。
2. 创建型模式
2.1 单例模式(Singleton)
确保一个类只有一个实例,并提供全局访问点。
实现 :利用闭包或 Symbol 控制实例。
const Singleton = (function() {
let instance;
function createInstance() {
return { data: 'single instance' };
}
return {
getInstance: function() {
if (!instance) instance = createInstance();
return instance;
}
};
})();
// ES6 类方式
class SingletonClass {
constructor() {
if (!SingletonClass.instance) {
SingletonClass.instance = this;
}
return SingletonClass.instance;
}
}
2.2 工厂模式(Factory Method)
将对象的创建与使用分离,通过一个函数返回不同类型的对象。
function Car(brand) {
this.brand = brand;
}
function Bike(brand) {
this.brand = brand;
}
function vehicleFactory(type, brand) {
switch(type) {
case 'car': return new Car(brand);
case 'bike': return new Bike(brand);
default: throw new Error('Unknown type');
}
}
抽象工厂:一组工厂方法,创建一系列相关对象。
2.3 建造者模式(Builder)
将复杂对象的构建过程分步完成,与表示分离。
class Burger {
constructor(builder) {
this.size = builder.size;
this.cheese = builder.cheese;
}
static Builder = class {
constructor(size) { this.size = size; }
addCheese() { this.cheese = true; return this; }
build() { return new Burger(this); }
}
}
const myBurger = new Burger.Builder('large').addCheese().build();
2.4 原型模式(Prototype)
通过克隆已有对象来创建新对象,利用 JavaScript 的原型链。
const carPrototype = {
init(brand) { this.brand = brand; return this; },
drive() { console.log(`Driving ${this.brand}`); }
};
const myCar = Object.create(carPrototype).init('Tesla');
// 或使用 ES6 类继承自动实现原型模式
3. 结构型模式
3.1 适配器模式(Adapter)
将一个类的接口转换成客户期望的另一个接口,解决接口不兼容。
class OldAPI {
request() { return 'old data'; }
}
class NewAPI {
fetch() { return 'new data'; }
}
// 适配器
class Adapter {
constructor(newAPI) { this.newAPI = newAPI; }
request() { return this.newAPI.fetch(); }
}
3.2 装饰器模式(Decorator)
动态给对象添加额外职责,不修改原有结构。JavaScript 中常用高阶函数或类装饰器(提案阶段)。
function withLogging(fn) {
return function(...args) {
console.log(`Calling ${fn.name}`);
return fn(...args);
};
}
const add = (a,b) => a+b;
const loggedAdd = withLogging(add);
3.3 代理模式(Proxy)
为另一个对象提供替身或占位符,控制对其的访问。ES6 原生 Proxy 可直接实现。
const target = { message: 'hello' };
const handler = {
get(obj, prop) {
if (prop === 'message') return obj[prop].toUpperCase();
return obj[prop];
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.message); // HELLO
3.4 外观模式(Facade)
为复杂子系统提供统一的简化接口。
class CPU { freeze() { /*...*/ } jump() { /*...*/ } execute() { /*...*/ } }
class Memory { load() { /*...*/ } }
class ComputerFacade {
constructor() { this.cpu = new CPU(); this.memory = new Memory(); }
start() {
this.cpu.freeze();
this.memory.load();
this.cpu.jump();
this.cpu.execute();
}
}
3.5 组合模式(Composite)
将对象组合成树形结构以表示"部分-整体"层次,使单个对象和组合对象有一致接口。
class Graphic { draw() {} }
class Circle extends Graphic { draw() { console.log('draw circle'); } }
class CompositeGraphic extends Graphic {
constructor() { super(); this.graphics = []; }
add(g) { this.graphics.push(g); }
draw() { this.graphics.forEach(g => g.draw()); }
}
4. 行为型模式
4.1 观察者模式(Observer)与发布订阅(Publish/Subscribe)
定义对象间的一对多依赖,当主题变化时通知所有观察者。发布订阅通过中间代理进一步解耦。
观察者(Subject 直接持有 Observer 列表):
class Subject {
constructor() { this.observers = []; }
attach(observer) { this.observers.push(observer); }
notify(data) { this.observers.forEach(obs => obs.update(data)); }
}
class Observer {
update(data) { console.log('received', data); }
}
发布订阅(事件中心):
const EventBus = {
events: {},
subscribe(event, callback) {
if (!this.events[event]) this.events[event] = [];
this.events[event].push(callback);
},
publish(event, data) {
if (this.events[event]) this.events[event].forEach(cb => cb(data));
}
};
4.2 策略模式(Strategy)
定义一系列算法,使其可以互相替换,算法的变化独立于使用算法的客户。
const strategies = {
plus: (a,b) => a+b,
minus: (a,b) => a-b,
};
function execute(strategy, a, b) {
return strategies[strategy](a,b);
}
console.log(execute('plus', 5, 3)); // 8
4.3 命令模式(Command)
将请求封装为对象,从而支持参数化、队列、日志、撤销等。
class Light { turnOn() { console.log('light on'); } }
class TurnOnCommand {
constructor(light) { this.light = light; }
execute() { this.light.turnOn(); }
}
class RemoteControl {
setCommand(cmd) { this.command = cmd; }
pressButton() { this.command.execute(); }
}
4.4 迭代器模式(Iterator)
提供一种方法顺序访问聚合对象中的元素,而不暴露其内部表示。JavaScript 内置 Symbol.iterator 支持。
const myIterable = {
items: [1,2,3],
[Symbol.iterator]() {
let index = 0;
return {
next: () => ({
value: this.items[index++],
done: index > this.items.length
})
};
}
};
for (let val of myIterable) console.log(val);
4.5 中介者模式(Mediator)
用一个中介对象封装一系列对象之间的交互,使对象不必显式相互引用。
class Mediator {
constructor() { this.colleagues = []; }
register(c) { this.colleagues.push(c); c.mediator = this; }
send(sender, msg) {
this.colleagues.forEach(c => { if (c !== sender) c.receive(msg); });
}
}
class Colleague {
constructor(name) { this.name = name; }
send(msg) { this.mediator.send(this, msg); }
receive(msg) { console.log(`${this.name} got ${msg}`); }
}
4.6 状态模式(State)
允许对象在其内部状态改变时改变其行为,看起来像是修改了它的类。
class Context {
constructor() { this.state = new StateA(); }
setState(state) { this.state = state; }
request() { this.state.handle(this); }
}
class StateA { handle(ctx) { console.log('state A'); ctx.setState(new StateB()); } }
class StateB { handle(ctx) { console.log('state B'); ctx.setState(new StateA()); } }
4.7 模板方法模式(Template Method)
在父类中定义算法的骨架,让子类实现具体步骤。
class Beverage {
boilWater() { console.log('boil water'); }
brew() { throw new Error('must override'); }
pourInCup() { console.log('pour in cup'); }
addCondiments() { throw new Error('must override'); }
prepare() {
this.boilWater();
this.brew();
this.pourInCup();
this.addCondiments();
}
}
class Coffee extends Beverage {
brew() { console.log('brew coffee'); }
addCondiments() { console.log('add sugar'); }
}
5. JavaScript 特有的设计模式
5.1 模块模式(Module Pattern)
利用立即执行函数表达式(IIFE)或 ES6 模块实现私有变量和封装。
// IIFE 模块
const module = (function() {
let privateVar = 0;
function privateMethod() {}
return {
publicMethod() { privateVar++; }
};
})();
// ES6 模块 (文件)
// export const publicVar = 1;
// export function publicMethod() {}
5.2 混入模式(Mixin)
将多个对象的属性和方法混合到一个对象,实现多重继承的效果。
const mixin = {
sayHi() { console.log(`Hi, I'm ${this.name}`); }
};
class Person {
constructor(name) { this.name = name; }
}
Object.assign(Person.prototype, mixin);
5.3 高阶组件模式(React 等框架中常见)
在 React 中,通过函数接收组件并返回增强后的新组件,属于装饰器模式的一种应用。
6. 现代 JavaScript 对设计模式的影响
1)ES6 类 :简化了构造函数、继承和 super 调用,使传统面向对象模式(如工厂、建造者)更易读。
2)Proxy 与 Reflect:原生支持代理模式,可实现元编程、数据劫持等。
3)模块系统 :原生模块(import/export)取代了以往的 IIFE 模块模式。
4)箭头函数:简化回调,在策略模式、观察者模式中更简洁。
5)Symbol :可用于定义私有属性(通过 Symbol.for)或防止属性名冲突。
6)Decorator 提案:未来可能提供标准的装饰器语法,简化装饰器模式。
7. 总结
设计模式是解决特定问题的经验总结,但使用时应注意:
1)不要过度设计:在简单场景下直接实现可能比套用模式更合适。
2)结合语言特性:JavaScript 的动态性允许用更简单的方式实现很多模式(如函数代替策略类)。
3)保持代码可读性:模式名称可作为代码注释,帮助团队理解意图。
深入理解设计模式,能帮助写出更健壮、可维护的 JavaScript 代码。在实际项目中,常用模式(如单例、观察者、策略、模块)几乎无处不在,值得熟练掌握。