JavaScript设计模式大全

2024-08-04 11:58:06 306
JavaScript 中的设计模式为开发者提供了一种处理常见软件设计问题的方法。这些设计模式可以帮助开发者创建更高效、更可维护的代码。下面是 JavaScript 中常见的设计模式,包括创建型、结构型和行为型模式,并附有详细的说明、使用场景和示例代码。

创建型模式

1. 工厂模式 (Factory Pattern)

描述:工厂模式通过定义一个创建对象的接口,但让子类决定实例化哪个类。工厂模式使得一个类的实例化过程与它的使用解耦。

使用场景:当系统中存在多个具有相似结构和功能的对象时,使用工厂模式可以简化对象创建的过程。

// 工厂函数:创建一个人对象
function createPerson(name, age) {
  return {
    name: name,
    age: age,
    greet() {
      console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
    }
  };
}

// 使用工厂函数创建对象
const person1 = createPerson('Alice', 30);
person1.greet(); // Hello, my name is Alice and I am 30 years old.

2. 构造函数模式 (Constructor Pattern)

描述:构造函数模式使用构造函数来创建对象,结合 new 关键字。这种模式允许创建多个相似类型的对象,并且可以在原型上定义方法,以便所有实例共享。

使用场景:当需要创建多个具有相同属性和方法的对象时,使用构造函数模式能够有效减少代码重复。

// 构造函数:定义一个人对象的构造函数
function Person(name, age) {
  this.name = name;
  this.age = age;
}

// 在构造函数的原型上定义方法
Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};

// 使用构造函数创建对象
const person2 = new Person('Bob', 25);
person2.greet(); // Hello, my name is Bob and I am 25 years old.

3. 单例模式 (Singleton Pattern)

描述:单例模式确保一个类只有一个实例,并提供一个全局访问点。这种模式常用于需要共享数据或控制访问的场景。

使用场景:当需要确保系统中只有一个实例(例如配置管理器、数据库连接等)时,单例模式是一个有效的选择。

// 单例模式:定义一个单例对象
const Singleton = (function() {
  let instance;

  function createInstance() {
    return {
      name: 'SingletonInstance',
      sayHello() {
        console.log('Hello, I am a singleton instance.');
      }
    };
  }

  return {
    getInstance() {
      if (!instance) {
        instance = createInstance();
      }
      return instance;
    }
  };
})();

// 获取单例实例
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();

console.log(instance1 === instance2); // true
instance1.sayHello(); // Hello, I am a singleton instance.

4. 原型模式 (Prototype Pattern)

描述:原型模式通过复制现有对象来创建新对象。这种模式在需要创建多个具有相同结构的对象时特别有用。

使用场景:当需要创建的对象有一个共同的结构或状态时,原型模式可以有效地重用这些结构或状态。

// 原型对象
const personPrototype = {
  greet() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  }
};

// 使用 Object.create 创建新对象并继承原型
const person3 = Object.create(personPrototype);
person3.name = 'Charlie';
person3.age = 40;
person3.greet(); // Hello, my name is Charlie and I am 40 years old.

5. 建造者模式 (Builder Pattern)

描述:建造者模式将对象的构建过程与表示分离,使得同样的构建过程可以创建不同的表示。

使用场景:当需要创建一个复杂对象,并且构建过程可以分步骤进行时,建造者模式提供了一个灵活的解决方案。

// 建造者模式:定义建造过程和表示
class PersonBuilder {
  constructor() {
    this.person = {};
  }

  setName(name) {
    this.person.name = name;
    return this;
  }

  setAge(age) {
    this.person.age = age;
    return this;
  }

  setGender(gender) {
    this.person.gender = gender;
    return this;
  }

  build() {
    return this.person;
  }
}

// 使用建造者模式创建对象
const person4 = new PersonBuilder()
  .setName('Dave')
  .setAge(35)
  .setGender('Male')
  .build();

console.log(person4); // { name: 'Dave', age: 35, gender: 'Male' }

结构型模式

6. 适配器模式 (Adapter Pattern)

描述:适配器模式用于将一个接口转换成客户希望的另一个接口,使得接口不兼容的类可以一起工作。

使用场景:当需要将一个已有的类或接口与现有系统集成,但它们的接口不兼容时,适配器模式是一个有效的解决方案。

// 适配器模式:适配不同接口的方法
// 原有类
class OldPrinter {
  oldPrint() {
    console.log('Printing using old method...');
  }
}

// 新接口类
class NewPrinter {
  newPrint() {
    console.log('Printing using new method...');
  }
}

// 适配器类:将新接口适配为旧接口
class PrinterAdapter {
  constructor(newPrinter) {
    this.newPrinter = newPrinter;
  }

  oldPrint() {
    this.newPrinter.newPrint();
  }
}

// 使用旧接口
const oldPrinter = new OldPrinter();
oldPrinter.oldPrint(); // Printing using old method...

// 使用适配器
const newPrinter = new NewPrinter();
const adapter = new PrinterAdapter(newPrinter);
adapter.oldPrint(); // Printing using new method...

7. 装饰者模式 (Decorator Pattern)

描述:装饰者模式在不改变对象结构的情况下,动态地给对象添加职责。装饰者模式通过创建一个包装对象,即装饰者,来扩展对象的功能。

使用场景:当需要动态添加对象的功能,而不影响其他对象时,装饰者模式提供了一种灵活的方式。

// 装饰者模式:为对象动态添加新功能
// 原有对象
class Coffee {
  cost() {
    return 5;
  }
}

// 装饰者:添加牛奶功能
class MilkDecorator {
  constructor(coffee) {
    this.coffee = coffee;
  }

  cost() {
    return this.coffee.cost() + 1; // 添加牛奶的费用
  }
}

// 装饰者:添加糖功能
class SugarDecorator {
  constructor(coffee) {
    this.coffee = coffee;
  }

  cost() {
    return this.coffee.cost() + 0.5; // 添加糖的费用
  }
}

// 使用装饰者模式
let coffee = new Coffee();
coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);
console.log(`Cost: $${coffee.cost()}`); // Cost: $6.5

8. 外观模式 (Facade Pattern)

描述:外观模式为一组复杂的子系统提供一个更高级的统一接口,使得子系统的使用更为简单。

使用场景:当系统中的子系统复杂且需要简化其接口时,外观模式提供了一个易于使用的接口。

// 外观模式:简化复杂子系统的使用
// 子系统1
class CPU {
  start() {
    console.log('CPU started');
  }

  shutdown() {
    console.log('CPU shut down');
  }
}

// 子系统2
class Memory {
  load() {
    console.log('Memory loaded');
  }

  unload() {
    console.log('Memory unloaded');
  }
}

// 子系统3
class HardDrive {
  read() {
    console.log('Hard drive read');
  }

  write() {
    console.log('Hard drive written');
  }
}

// 外观类:为复杂的子系统提供一个简化的接口
class ComputerFacade {
  constructor() {
    this.cpu = new CPU();
    this.memory = new Memory();
    this.hardDrive = new HardDrive();
  }

  start() {
    this.cpu.start();
    this.memory.load();
    this.hardDrive.read();
    console.log('Computer started');
  }

  shutdown() {
    this.cpu.shutdown();
    this.memory.unload();
    this.hardDrive.write();
    console.log('Computer shut down');
  }
}

// 使用外观类
const computer = new ComputerFacade();
computer.start(); // 启动计算机
computer.shutdown(); // 关闭计算机

9. 组合模式 (Composite Pattern)

描述:组合

模式将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

使用场景:当需要处理一个对象及其子对象的树形结构时,组合模式提供了有效的管理方法。

// 组合模式:表示树形结构
// 组件接口
class Component {
  constructor(name) {
    this.name = name;
  }

  operation() {
    throw new Error('Operation method not implemented');
  }
}

// 叶子节点
class Leaf extends Component {
  operation() {
    console.log(`Leaf ${this.name} operation`);
  }
}

// 组合节点
class Composite extends Component {
  constructor(name) {
    super(name);
    this.children = [];
  }

  add(child) {
    this.children.push(child);
  }

  operation() {
    console.log(`Composite ${this.name} operation`);
    this.children.forEach(child => child.operation());
  }
}

// 使用组合模式
const leaf1 = new Leaf('Leaf1');
const leaf2 = new Leaf('Leaf2');
const composite = new Composite('Composite');
composite.add(leaf1);
composite.add(leaf2);
composite.operation();
// Composite Composite operation
// Leaf Leaf1 operation
// Leaf Leaf2 operation

10. 代理模式 (Proxy Pattern)

描述:代理模式通过代理对象来控制对其他对象的访问。代理对象提供了对真实对象的控制和管理,可以在访问前后进行处理。

使用场景:当需要控制对一个对象的访问,或在访问前后进行处理时,代理模式提供了一个有效的解决方案。

// 代理模式:控制对真实对象的访问
// 真实对象
class RealSubject {
  request() {
    console.log('RealSubject request');
  }
}

// 代理对象
class Proxy {
  constructor(realSubject) {
    this.realSubject = realSubject;
  }

  request() {
    console.log('Proxy request');
    this.realSubject.request();
  }
}

// 使用代理模式
const realSubject = new RealSubject();
const proxy = new Proxy(realSubject);
proxy.request();
// Proxy request
// RealSubject request

行为型模式

11. 观察者模式 (Observer Pattern)

描述:观察者模式定义了一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象的状态发生变化时,所有观察者都会收到通知。

使用场景:当一个对象的状态改变时,需要通知多个其他对象,而不需要知道这些对象的具体实现时,观察者模式是一个有效的选择。

// 观察者模式:定义主题和观察者
// 主题类
class Subject {
  constructor() {
    this.observers = [];
  }

  addObserver(observer) {
    this.observers.push(observer);
  }

  removeObserver(observer) {
    this.observers = this.observers.filter(o => o !== observer);
  }

  notifyObservers(message) {
    this.observers.forEach(observer => observer.update(message));
  }
}

// 观察者接口
class Observer {
  update(message) {
    throw new Error('Update method not implemented');
  }
}

// 具体观察者类
class ConcreteObserver extends Observer {
  update(message) {
    console.log(`Observer received message: ${message}`);
  }
}

// 使用观察者模式
const subject = new Subject();
const observer1 = new ConcreteObserver();
const observer2 = new ConcreteObserver();
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notifyObservers('Hello Observers!');
// Observer received message: Hello Observers!
// Observer received message: Hello Observers!

12. 策略模式 (Strategy Pattern)

描述:策略模式定义一系列算法,将每一个算法封装起来,使它们可以互换。策略模式让算法的变化独立于使用算法的客户。

使用场景:当需要在运行时选择不同的算法或策略时,策略模式可以帮助将算法与使用算法的代码分离开来。

// 策略模式:定义不同的算法
// 策略接口
class Strategy {
  execute(a, b) {
    throw new Error('Execute method not implemented');
  }
}

// 具体策略类1:加法
class AddStrategy extends Strategy {
  execute(a, b) {
    return a + b;
  }
}

// 具体策略类2:减法
class SubtractStrategy extends Strategy {
  execute(a, b) {
    return a - b;
  }
}

// 上下文类:使用策略
class Context {
  constructor(strategy) {
    this.strategy = strategy;
  }

  executeStrategy(a, b) {
    return this.strategy.execute(a, b);
  }
}

// 使用策略模式
const addStrategy = new AddStrategy();
const subtractStrategy = new SubtractStrategy();

const context = new Context(addStrategy);
console.log(context.executeStrategy(10, 5)); // 15

context.strategy = subtractStrategy;
console.log(context.executeStrategy(10, 5)); // 5

13. 模板方法模式 (Template Method Pattern)

描述:模板方法模式定义一个操作的算法,并将一些步骤的实现推迟到子类。模板方法让子类在不改变算法结构的情况下重新定义算法的某些步骤。

使用场景:当有一个通用的操作流程,而该流程的某些步骤可能会因子类而异时,模板方法模式可以提供一种灵活的方式来处理这些变化。

// 模板方法模式:定义操作的模板
class AbstractClass {
  templateMethod() {
    this.step1();
    this.step2();
    this.step3();
  }

  step1() {
    console.log('Step 1');
  }

  step2() {
    throw new Error('Step 2 must be implemented');
  }

  step3() {
    console.log('Step 3');
  }
}

// 具体实现类:实现模板方法的步骤
class ConcreteClass extends AbstractClass {
  step2() {
    console.log('Step 2 implementation');
  }
}

// 使用模板方法模式
const instance = new ConcreteClass();
instance.templateMethod();
// Step 1
// Step 2 implementation
// Step 3

14. 状态模式 (State Pattern)

描述:状态模式允许一个对象在其内部状态改变时改变其行为。状态模式将状态的变化封装到状态对象中,使得状态之间的切换更加灵活。

使用场景:当一个对象的行为依赖于其状态,并且可以在运行时改变其状态时,状态模式可以提供一种有效的管理方式。

// 状态模式:定义状态及其行为
class State {
  handle() {
    throw new Error('Handle method not implemented');
  }
}

class ConcreteStateA extends State {
  handle() {
    console.log('Handling in State A');
  }
}

class ConcreteStateB extends State {
  handle() {
    console.log('Handling in State B');
  }
}

// 上下文类:管理状态
class Context {
  constructor(state) {
    this.state = state;
  }

  setState(state) {
    this.state = state;
  }

  request() {
    this.state.handle();
  }
}

// 使用状态模式
const context = new Context(new ConcreteStateA());
context.request(); // Handling in State A

context.setState(new ConcreteStateB());
context.request(); // Handling in State B

15. 责任链模式 (Chain of Responsibility Pattern)

描述:责任链模式将请求沿着处理链传递,每个处理对象都有机会处理请求,或者将请求传递给下一个处理对象。责任链模式允许多个对象有机会处理请求。

使用场景:当需要多个对象处理同一个请求,且处理的顺序不确定时,责任链模式可以有效地组织这些处理对象。

// 责任链模式:定义处理链及处理者
class Handler {
  constructor(successor) {
    this.successor = successor;
  }

  handleRequest(request) {
    if (this.successor) {
      this.successor.handleRequest(request);
    }
  }
}

class ConcreteHandlerA extends Handler {
  handleRequest(request) {
    if (request === 'A') {
      console.log('Handler A handled the request');
    } else {
      super.handleRequest(request);
    }
  }
}

class ConcreteHandlerB extends Handler {
  handleRequest(request) {
    if (request === 'B') {
      console.log('Handler B handled the request');
    } else {
      super.handleRequest(request);
    }
  }
}

// 使用责任链模式
const handlerB = new ConcreteHandlerB();
const handlerA = new ConcreteHandlerA(handlerB);

handlerA.handleRequest('A'); // Handler A handled the request
handlerA.handleRequest('B'); // Handler B handled the request

16. 迭代器模式 (Iterator Pattern)

描述:迭代器模式提供一种顺序访问聚合对象中的元素而无需暴露其内部表示的方法。迭代器模式通过迭代器对象提供访问集合元素的标准接口。

使用场景:当需要遍历一个集合的元素,而不需要了解集合的内部结构时,迭代器模式提供了一种简洁的方法。

// 迭代器模式:定义迭代器接口及集合
class Iterator {
  constructor(collection) {
    this.collection

 = collection;
    this.index = 0;
  }

  next() {
    if (this.hasNext()) {
      return this.collection[this.index++];
    }
    return null;
  }

  hasNext() {
    return this.index < this.collection.length;
  }
}

// 使用迭代器模式
const collection = ['item1', 'item2', 'item3'];
const iterator = new Iterator(collection);

while (iterator.hasNext()) {
  console.log(iterator.next());
}
// item1
// item2
// item3

17. 中介者模式 (Mediator Pattern)

描述:中介者模式通过定义一个中介对象来封装一组对象之间的交互。中介者模式使得各个对象之间的通信不直接发生,从而减少对象之间的依赖。

使用场景:当系统中的对象之间有复杂的交互关系时,中介者模式可以帮助简化这些关系,使系统更易于维护。

// 中介者模式:定义中介者及参与者
class Mediator {
  constructor() {
    this.components = {};
  }

  register(name, component) {
    this.components[name] = component;
  }

  relay(sender, message) {
    Object.keys(this.components).forEach(name => {
      if (name !== sender) {
        this.components[name].receive(message);
      }
    });
  }
}

class Component {
  constructor(name, mediator) {
    this.name = name;
    this.mediator = mediator;
    this.mediator.register(name, this);
  }

  send(message) {
    console.log(`${this.name} sending message: ${message}`);
    this.mediator.relay(this.name, message);
  }

  receive(message) {
    console.log(`${this.name} received message: ${message}`);
  }
}

// 使用中介者模式
const mediator = new Mediator();
const componentA = new Component('ComponentA', mediator);
const componentB = new Component('ComponentB', mediator);

componentA.send('Hello from ComponentA');
// ComponentA sending message: Hello from ComponentA
// ComponentB received message: Hello from ComponentA

18. 备忘录模式 (Memento Pattern)

描述:备忘录模式允许保存和恢复对象的内部状态,而不暴露对象的内部结构。备忘录模式使得对象的状态可以在需要时恢复到先前的状态。

使用场景:当需要保存对象的某个状态,以便在未来可以恢复到该状态时,备忘录模式提供了一种便捷的解决方案。

// 备忘录模式:定义备忘录及其管理
class Memento {
  constructor(state) {
    this.state = state;
  }
}

class Originator {
  constructor() {
    this.state = '';
  }

  setState(state) {
    this.state = state;
  }

  saveStateToMemento() {
    return new Memento(this.state);
  }

  getStateFromMemento(memento) {
    this.state = memento.state;
  }
}

// 使用备忘录模式
const originator = new Originator();
originator.setState('State1');
const memento = originator.saveStateToMemento();

originator.setState('State2');
console.log(originator.state); // State2

originator.getStateFromMemento(memento);
console.log(originator.state); // State1

19. 访问者模式 (Visitor Pattern)

描述:访问者模式将数据结构与操作分离,使得可以在不修改数据结构的情况下定义新的操作。访问者模式允许通过访问者对象对对象结构中的元素进行操作。

使用场景:当需要在不改变对象结构的情况下对对象结构中的元素进行操作时,访问者模式可以提供一种灵活的解决方案。

// 访问者模式:定义访问者及被访问者
class Visitor {
  visit(element) {
    throw new Error('Visit method not implemented');
  }
}

class ConcreteVisitorA extends Visitor {
  visit(element) {
    console.log('ConcreteVisitorA visiting', element);
  }
}

class ConcreteVisitorB extends Visitor {
  visit(element) {
    console.log('ConcreteVisitorB visiting', element);
  }
}

class Element {
  accept(visitor) {
    visitor.visit(this);
  }
}

// 使用访问者模式
const element = new Element();
const visitorA = new ConcreteVisitorA();
const visitorB = new ConcreteVisitorB();

element.accept(visitorA); // ConcreteVisitorA visiting Element
element.accept(visitorB); // ConcreteVisitorB visiting Element

以上是 JavaScript 中常见的设计模式及其示例。每种模式都有其适用场景和特点,可以根据具体需求选择合适的设计模式来优化代码结构。