前端那点事:2025你还不了解JavaScript 的设计模式?
·
文章目录
前言
我们通常将设计模式分为三大类:创建型、结构型和行为型。下面我将介绍一些在JavaScript中常见的设计模式,并给出相应的代码示例。
设计模式是解决软件设计中常见问题的可重用方案。在 JavaScript 中,设计模式的应用有其独特的特点。
一、创建型模式
示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。
1. 单例模式 (Singleton)
class Singleton {
constructor() {
if (Singleton.instance) {
return Singleton.instance;
}
Singleton.instance = this;
this.data = [];
return this;
}
static getInstance() {
if (!Singleton.instance) {
Singleton.instance = new Singleton();
}
return Singleton.instance;
}
addData(item) {
this.data.push(item);
}
getData() {
return this.data;
}
}
// 使用
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // true
// 或者使用闭包实现
const SingletonClosure = (function() {
let instance;
function createInstance() {
return {
data: [],
addData(item) {
this.data.push(item);
}
};
}
return {
getInstance: function() {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
2. 工厂模式 (Factory)
创建对象而不暴露创建逻辑。
// 简单工厂
class Car {
constructor(type, price) {
this.type = type;
this.price = price;
}
drive() {
console.log(`${this.type} is driving`);
}
}
class CarFactory {
static createCar(type) {
switch(type) {
case 'sedan':
return new Car('Sedan', 20000);
case 'suv':
return new Car('SUV', 30000);
case 'sports':
return new Car('Sports', 50000);
default:
throw new Error('Unknown car type');
}
}
}
// 使用
const sedan = CarFactory.createCar('sedan');
const suv = CarFactory.createCar('suv');
// 抽象工厂
class AbstractVehicleFactory {
constructor() {
this.types = {};
}
registerVehicle(type, VehicleClass) {
this.types[type] = VehicleClass;
}
createVehicle(type, options) {
const Vehicle = this.types[type];
if (!Vehicle) {
throw new Error('Unknown vehicle type');
}
return new Vehicle(options);
}
}
// 具体类
class Bike {
constructor(options) {
this.wheels = 2;
this.color = options.color;
}
}
class Truck {
constructor(options) {
this.wheels = 6;
this.color = options.color;
}
}
// 使用
const factory = new AbstractVehicleFactory();
factory.registerVehicle('bike', Bike);
factory.registerVehicle('truck', Truck);
const bike = factory.createVehicle('bike', { color: 'red' });
const truck = factory.createVehicle('truck', { color: 'blue' });
3. 建造者模式 (Builder)
逐步构建复杂对象。
class Pizza {
constructor() {
this.size = null;
this.crust = null;
this.toppings = [];
this.sauce = null;
this.cheese = null;
}
describe() {
return `Pizza: ${this.size} size, ${this.crust} crust, ${this.sauce} sauce, ${this.cheese} cheese, toppings: ${this.toppings.join(', ')}`;
}
}
class PizzaBuilder {
constructor() {
this.pizza = new Pizza();
}
setSize(size) {
this.pizza.size = size;
return this;
}
setCrust(crust) {
this.pizza.crust = crust;
return this;
}
addTopping(topping) {
this.pizza.toppings.push(topping);
return this;
}
setSauce(sauce) {
this.pizza.sauce = sauce;
return this;
}
setCheese(cheese) {
this.pizza.cheese = cheese;
return this;
}
build() {
return this.pizza;
}
}
// 使用
const pizza = new PizzaBuilder()
.setSize('large')
.setCrust('thin')
.addTopping('pepperoni')
.addTopping('mushrooms')
.setSauce('tomato')
.setCheese('mozzarella')
.build();
console.log(pizza.describe());
4. 原型模式 (Prototype)
通过克隆现有对象来创建新对象。
// 使用 Object.create
const carPrototype = {
wheels: 4,
start() {
console.log('Car started');
},
stop() {
console.log('Car stopped');
}
};
const myCar = Object.create(carPrototype);
myCar.color = 'red';
myCar.brand = 'Toyota';
// 或者使用类
class Car {
constructor(brand, color) {
this.brand = brand;
this.color = color;
this.wheels = 4;
}
start() {
console.log(`${this.brand} started`);
}
stop() {
console.log(`${this.brand} stopped`);
}
clone() {
return Object.create(Object.getPrototypeOf(this),
Object.getOwnPropertyDescriptors(this));
}
}
const originalCar = new Car('Honda', 'blue');
const clonedCar = originalCar.clone();
二、结构型模式
1. 适配器模式 (Adapter)
让不兼容的接口能够一起工作。
// 老接口
class OldCalculator {
operations(a, b, operation) {
switch(operation) {
case 'add':
return a + b;
case 'sub':
return a - b;
default:
return NaN;
}
}
}
// 新接口
class NewCalculator {
add(a, b) {
return a + b;
}
subtract(a, b) {
return a - b;
}
}
// 适配器
class CalculatorAdapter {
constructor() {
this.newCalculator = new NewCalculator();
}
operations(a, b, operation) {
switch(operation) {
case 'add':
return this.newCalculator.add(a, b);
case 'sub':
return this.newCalculator.subtract(a, b);
default:
return NaN;
}
}
}
// 使用
const adapter = new CalculatorAdapter();
console.log(adapter.operations(5, 3, 'add')); // 8
2. 装饰器模式 (Decorator)
动态地为对象添加新功能。
// ES6 类装饰器
function withFuelReport(constructor) {
return class extends constructor {
fuelReport() {
console.log(`Fuel level: ${this.fuel}%`);
}
};
}
@withFuelReport
class Car {
constructor() {
this.fuel = 100;
}
}
// 属性装饰器
function readonly(target, property, descriptor) {
descriptor.writable = false;
return descriptor;
}
class Person {
constructor(name) {
this.name = name;
}
@readonly
get name() {
return this._name;
}
}
// 函数式装饰器
function loggerDecorator(fn) {
return function(...args) {
console.log(`Calling ${fn.name} with arguments:`, args);
const result = fn.apply(this, args);
console.log(`Result:`, result);
return result;
};
}
class MathOperations {
@loggerDecorator
add(a, b) {
return a + b;
}
}
3. 代理模式 (Proxy)
为其他对象提供一种代理以控制对这个对象的访问。
// 虚拟代理 - 延迟创建昂贵对象
class ExpensiveObject {
constructor() {
console.log('Creating expensive object...');
// 模拟昂贵操作
}
process() {
console.log('Processing...');
}
}
class ExpensiveObjectProxy {
constructor() {
this.realObject = null;
}
process() {
if (!this.realObject) {
this.realObject = new ExpensiveObject();
}
this.realObject.process();
}
}
// 保护代理 - 控制访问
const person = {
name: 'John',
age: 30,
password: 'secret'
};
const personProxy = new Proxy(person, {
get(target, property) {
if (property === 'password') {
throw new Error('Access denied to password');
}
return target[property];
},
set(target, property, value) {
if (property === 'age' && (value < 0 || value > 150)) {
throw new Error('Invalid age');
}
target[property] = value;
return true;
}
});
// 缓存代理
function cacheDecorator(fn) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
console.log('Returning cached result');
return cache.get(key);
}
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
}
const expensiveCalculation = cacheDecorator(function(n) {
console.log('Performing expensive calculation...');
return n * n;
});
4. 外观模式 (Facade)
为复杂的子系统提供简化的接口。
class CPU {
start() {
console.log('CPU starting...');
}
execute() {
console.log('CPU executing...');
}
}
class Memory {
load() {
console.log('Memory loading...');
}
}
class HardDrive {
read() {
console.log('HardDrive reading...');
}
}
// 外观类
class ComputerFacade {
constructor() {
this.cpu = new CPU();
this.memory = new Memory();
this.hardDrive = new HardDrive();
}
start() {
console.log('Computer starting...');
this.cpu.start();
this.memory.load();
this.hardDrive.read();
this.cpu.execute();
console.log('Computer ready!');
}
}
// 使用
const computer = new ComputerFacade();
computer.start();
三、行为型模式
1. 观察者模式 (Observer)
定义对象间的一对多依赖关系。
class Subject {
constructor() {
this.observers = [];
}
subscribe(observer) {
this.observers.push(observer);
}
unsubscribe(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notify(data) {
this.observers.forEach(observer => observer.update(data));
}
}
class Observer {
constructor(name) {
this.name = name;
}
update(data) {
console.log(`${this.name} received:`, data);
}
}
// 使用
const subject = new Subject();
const observer1 = new Observer('Observer 1');
const observer2 = new Observer('Observer 2');
subject.subscribe(observer1);
subject.subscribe(observer2);
subject.notify('Hello World!');
// 更现代的 EventEmitter 实现
class EventEmitter {
constructor() {
this.events = {};
}
on(event, listener) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(listener);
}
off(event, listener) {
if (!this.events[event]) return;
this.events[event] = this.events[event].filter(l => l !== listener);
}
emit(event, data) {
if (!this.events[event]) return;
this.events[event].forEach(listener => listener(data));
}
once(event, listener) {
const onceWrapper = (data) => {
listener(data);
this.off(event, onceWrapper);
};
this.on(event, onceWrapper);
}
}
2. 策略模式 (Strategy)
定义一系列算法,使其可以互相替换。
class PaymentStrategy {
pay(amount) {
throw new Error('Method not implemented');
}
}
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 CryptoStrategy extends PaymentStrategy {
pay(amount) {
console.log(`Paid ${amount} using Cryptocurrency`);
}
}
class ShoppingCart {
constructor() {
this.amount = 0;
this.strategy = null;
}
setPaymentStrategy(strategy) {
this.strategy = strategy;
}
addItem(price) {
this.amount += price;
}
checkout() {
if (!this.strategy) {
throw new Error('No payment strategy set');
}
this.strategy.pay(this.amount);
this.amount = 0;
}
}
// 使用
const cart = new ShoppingCart();
cart.addItem(100);
cart.addItem(50);
cart.setPaymentStrategy(new CreditCardStrategy());
cart.checkout(); // Paid 150 using Credit Card
cart.addItem(75);
cart.setPaymentStrategy(new PayPalStrategy());
cart.checkout(); // Paid 75 using PayPal
3. 命令模式 (Command)
将请求封装为对象。
class Command {
execute() {
throw new Error('Method not implemented');
}
undo() {
throw new Error('Method not implemented');
}
}
class LightOnCommand extends Command {
constructor(light) {
super();
this.light = light;
}
execute() {
this.light.turnOn();
}
undo() {
this.light.turnOff();
}
}
class LightOffCommand extends Command {
constructor(light) {
super();
this.light = light;
}
execute() {
this.light.turnOff();
}
undo() {
this.light.turnOn();
}
}
class Light {
constructor() {
this.isOn = false;
}
turnOn() {
this.isOn = true;
console.log('Light is ON');
}
turnOff() {
this.isOn = false;
console.log('Light is OFF');
}
}
class RemoteControl {
constructor() {
this.commands = [];
this.history = [];
}
setCommand(command) {
this.commands.push(command);
}
executeCommands() {
this.commands.forEach(command => {
command.execute();
this.history.push(command);
});
this.commands = [];
}
undo() {
if (this.history.length > 0) {
const command = this.history.pop();
command.undo();
}
}
}
// 使用
const light = new Light();
const remote = new RemoteControl();
remote.setCommand(new LightOnCommand(light));
remote.setCommand(new LightOffCommand(light));
remote.executeCommands();
remote.undo(); // Undo last command
4. 状态模式 (State)
允许对象在内部状态改变时改变其行为。
class State {
constructor(context) {
this.context = context;
}
handle() {
throw new Error('Method not implemented');
}
}
class RedState extends State {
handle() {
console.log('Red Light - STOP');
this.context.setState(new GreenState(this.context));
}
}
class GreenState extends State {
handle() {
console.log('Green Light - GO');
this.context.setState(new YellowState(this.context));
}
}
class YellowState extends State {
handle() {
console.log('Yellow Light - CAUTION');
this.context.setState(new RedState(this.context));
}
}
class TrafficLight {
constructor() {
this.state = new RedState(this);
}
setState(state) {
this.state = state;
}
change() {
this.state.handle();
}
}
// 使用
const trafficLight = new TrafficLight();
trafficLight.change(); // Red Light - STOP
trafficLight.change(); // Green Light - GO
trafficLight.change(); // Yellow Light - CAUTION
四、JavaScript 特有模式
1. 模块模式
// IIFE 模块模式
const MyModule = (function() {
let privateVariable = 0;
function privateMethod() {
return privateVariable;
}
return {
publicMethod: function() {
privateVariable++;
return privateMethod();
},
getValue: function() {
return privateVariable;
}
};
})();
// ES6 模块模式
const module = (function() {
const privateData = new WeakMap();
class MyClass {
constructor(data) {
privateData.set(this, { data });
}
getData() {
return privateData.get(this).data;
}
}
return MyClass;
})();
2. 混入模式 (Mixin)
// 简单的混入函数
function mixin(target, ...sources) {
Object.assign(target, ...sources);
}
const CanEat = {
eat(food) {
console.log(`${this.name} is eating ${food}`);
}
};
const CanSleep = {
sleep() {
console.log(`${this.name} is sleeping`);
}
};
class Animal {
constructor(name) {
this.name = name;
}
}
// 应用混入
mixin(Animal.prototype, CanEat, CanSleep);
const dog = new Animal('Dog');
dog.eat('meat');
dog.sleep();
// 函数式混入
const Flyable = Base => class extends Base {
fly() {
console.log(`${this.name} is flying`);
}
};
class Bird extends Flyable(Animal) {
constructor(name) {
super(name);
}
}
const eagle = new Bird('Eagle');
eagle.fly();
3. 中间件模式
class Middleware {
constructor() {
this.middlewares = [];
}
use(fn) {
this.middlewares.push(fn);
}
execute(context) {
const executeMiddleware = (index) => {
if (index < this.middlewares.length) {
const middleware = this.middlewares[index];
middleware(context, () => executeMiddleware(index + 1));
}
};
executeMiddleware(0);
}
}
// 使用
const middleware = new Middleware();
middleware.use((ctx, next) => {
console.log('Middleware 1 - start');
ctx.data = 'Hello';
next();
console.log('Middleware 1 - end');
});
middleware.use((ctx, next) => {
console.log('Middleware 2 - start');
ctx.data += ' World';
next();
console.log('Middleware 2 - end');
});
const context = {};
middleware.execute(context);
console.log('Result:', context.data);
总结
最佳实践
-
根据需求选择模式: 不要为了使用模式而使用模式
-
保持简单: JavaScript 的动态特性有时可以避免复杂模式
-
考虑性能: 某些模式可能带来性能开销
-
利用语言特性: 充分利用 JavaScript 的原型、闭包等特性
-
代码可读性: 确保模式的使用提高了代码的可读性和可维护性
这些设计模式在 JavaScript 开发中非常有用,但需要根据具体场景灵活运用。
更多推荐


所有评论(0)