JavaScript 设计模式:从理论到实践
设计模式是解决常见问题的成熟方案。本文介绍 JavaScript 中最常用的几种设计模式,以及如何在实际项目中应用它们
2024-06-01
单例模式
确保一个类只有一个实例,并提供一个全局访问点。
class Singleton {
static #instance = null;
constructor() {
if (Singleton.#instance) {
return Singleton.#instance;
}
Singleton.#instance = this;
}
static getInstance() {
if (!Singleton.#instance) {
Singleton.#instance = new Singleton();
}
return Singleton.#instance;
}
}
// 使用
const a = Singleton.getInstance();
const b = Singleton.getInstance();
console.log(a === b); // true
工厂模式
根据参数创建不同类型的对象,隐藏创建逻辑。
class ButtonFactory {
create(type) {
switch(type) {
case 'primary':
return new PrimaryButton();
case 'secondary':
return new SecondaryButton();
case 'danger':
return new DangerButton();
default:
throw new Error('Unknown button type');
}
}
}
观察者模式
定义对象间的一对多依赖,当一个对象改变时,所有依赖者都会收到通知。
class EventEmitter {
#listeners = new Map();
on(event, callback) {
if (!this.#listeners.has(event)) {
this.#listeners.set(event, []);
}
this.#listeners.get(event).push(callback);
}
emit(event, data) {
const callbacks = this.#listeners.get(event) || [];
callbacks.forEach(cb => cb(data));
}
off(event, callback) {
const callbacks = this.#listeners.get(event) || [];
const index = callbacks.indexOf(callback);
if (index > -1) {
callbacks.splice(index, 1);
}
}
}
// 使用
const emitter = new EventEmitter();
emitter.on('data', (value) => console.log(value));
emitter.emit('data', 'Hello World');
策略模式
定义一系列算法,把它们一个个封装起来,并且使它们可以互相替换。
const strategies = {
creditCard: {
pay(amount) {
console.log(`Paid ${amount} using Credit Card`);
}
},
paypal: {
pay(amount) {
console.log(`Paid ${amount} using PayPal`);
}
},
crypto: {
pay(amount) {
console.log(`Paid ${amount} using Crypto`);
}
}
};
class PaymentContext {
setStrategy(strategy) {
this.strategy = strategy;
}
pay(amount) {
this.strategy.pay(amount);
}
}
// 使用
const payment = new PaymentContext();
payment.setStrategy(strategies.paypal);
payment.pay(100);
装饰器模式
动态地给对象添加额外的职责。
function withLogging(fn) {
return function(...args) {
console.log(`Calling ${fn.name} with`, args);
const result = fn.apply(this, args);
console.log(`Result:`, result);
return result;
};
}
function add(a, b) {
return a + b;
}
const loggedAdd = withLogging(add);
loggedAdd(2, 3); // 输出调用日志
总结
设计模式不是银弹,但它们是经过验证的解决方案。重要的是理解每种模式背后的思想,而不是生搬硬套。在实际项目中,通常会根据需要组合多种模式,或者对经典模式进行变体。
"设计模式的出现是为了复用成功的解决方案,让代码更加灵活、可维护。" — GoF