前言

我们通常将设计模式分为三大类:创建型、结构型和行为型。下面我将介绍一些在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);

总结

最佳实践

  1. 根据需求选择模式: 不要为了使用模式而使用模式

  2. 保持简单: JavaScript 的动态特性有时可以避免复杂模式

  3. 考虑性能: 某些模式可能带来性能开销

  4. 利用语言特性: 充分利用 JavaScript 的原型、闭包等特性

  5. 代码可读性: 确保模式的使用提高了代码的可读性和可维护性

这些设计模式在 JavaScript 开发中非常有用,但需要根据具体场景灵活运用。

更多推荐