JavaScript设计模式:让你的代码像个天才!

61,154 阅读11分钟

你是否曾经在JavaScript代码中迷失过?
是否曾经感到自己的代码像一团乱麻?
别担心,这就是我们需要设计模式的时候了!
让我们一起探索这些神奇的模式,让你的代码变得像个天才!

序言

总体来说设计模式分为三大类:

创建型模式: 工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式: 适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式: 策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

准备好了吗?让我们一起进入JavaScript设计模式的神奇世界,让你的代码变得像Tony Stark一样聪明!

工厂方法模式(Factory Method Pattern)

工厂方法模式定义了一个创建对象的接口,但是由子类决定要实例化的类是哪一个。可以将对象的创建和使用分离,使得系统更加灵活。其代码示例如下:

// 定义一个抽象类
class Animal {
  speak() {
    throw new Error('This method must be implemented.');
  }
}

// 实现具体的类
class Dog extends Animal {
  speak() {
    return 'Woof!';
  }
}

class Cat extends Animal {
  speak() {
    return 'Meow!';
  }
}

// 实现工厂方法
class AnimalFactory {
  createAnimal(animalType) {
      switch(animalType) {
        case 'dog':
          return new Dog();
        case 'cat':
          return new Cat();
        default:
          throw new Error(`Invalid animal type: ${animalType}`);
      }
  }
}

// 使用工厂方法创建对象
const animalFactory = new AnimalFactory();
const dog = animalFactory.createAnimal('dog');
console.log(dog.speak()); // Output: Woof!
const cat = animalFactory.createAnimal('cat');
console.log(cat.speak()); // Output: Meow!

抽象工厂模式(Abstract Factory Pattern)

抽象工厂模式提供了一种封装一组具有相同主题的单个工厂的方式。它有一个接口,用于创建相关或依赖对象的家族,而不需要指定实际实现的类。其代码示例如下:

// 创建一组主题对象类型的抽象类
class AnimalFood {
  provide() {
    throw new Error('This method must be implemented.');
  }
}

class AnimalToy {
  provide() {
    throw new Error('This method must be implemented.');
  }
}

// 创建一组具体代表家族的对象
class HighQualityDogFood extends AnimalFood {
  provide() {
    return 'High quality dog food';
  }
}

class HighQualityDogToy extends AnimalToy {
  provide() {
    return 'High quality dog toy';
  }
}

class CheapCatFood extends AnimalFood {
  provide() {
    return 'Cheap cat food';
  }
}

class CheapCatToy extends AnimalToy {
  provide() {
    return 'Cheap cat toy';
  }
}

// 创建一个抽象工厂
class AnimalProductsAbstractFactory {
  createFood() {
    throw new Error('This method must be implemented.');
  }

  createToy() {
    throw new Error('This method must be implemented.');
  }
}

// 创建具体工厂类
class HighQualityAnimalProductsFactory extends AnimalProductsAbstractFactory {
  createFood() {
    return new HighQualityDogFood();
  }

  createToy() {
    return new HighQualityDogToy();
  }
}

class CheapAnimalProductsFactory extends AnimalProductsAbstractFactory {
  createFood() {
    return new CheapCatFood();
  }

  createToy() {
    return new CheapCatToy();
  }
}

// 使用具体工厂类来创建相关的对象
const highQualityAnimalProductsFactory = new HighQualityAnimalProductsFactory();
console.log(highQualityAnimalProductsFactory.createFood().provide()); // Output: High quality dog food
console.log(highQualityAnimalProductsFactory.createToy().provide()); // Output: High quality dog toy

const cheapAnimalProductsFactory = new CheapAnimalProductsFactory();
console.log(cheapAnimalProductsFactory.createFood().provide()); // Output: Cheap cat food
console.log(cheapAnimalProductsFactory.createToy().provide()); // Output: Cheap cat toy

单例模式(Singleton Pattern)

单例模式的目的是确保一个类只有一个实例,并为该实例提供全局访问点。其代码示例如下:

class Logger {
  constructor() {
    if (!Logger.instance) {
      this.logs = [];
      Logger.instance = this;
    }

    return Logger.instance;
  }

  log(message) {
    this.logs.push(message);
    console.log(`Logger: ${message}`);
  }

  printLogCount() {
    console.log(`Number of logs: ${this.logs.length}`);
  }
}

// 可以使用全局变量来访问实例
const logger = new Logger();
Object.freeze(logger);

// 对于每个实例,输出应该是相同的
logger.log('First message'); // Output: Logger: First message
logger.printLogCount(); // Output: Number of logs: 1

const anotherLogger = new Logger(); // 此时返回一个已经存在的实例
anotherLogger.log('Second message'); // Output: Logger: Second message
anotherLogger.printLogCount(); // Output: Number of logs: 2

建造者模式(Builder Pattern)

建造者模式是一种对象创建设计模式,它旨在通过一步步的构建流程来创建复杂对象。其代码示例如下:

// 创建 Product 类
class Sandwich {
  constructor() {
    this.ingredients = [];
  }

  addIngredient(ingredient) {
    this.ingredients.push(ingredient);
  }

  toString() {
    return this.ingredients.join(', ');
  }
}

// 创建一个建造者类
class SandwichBuilder {
  constructor() {
    this.sandwich = new Sandwich();
  }

  reset() {
    this.sandwich = new Sandwich();
  }

  putMeat(meat) {
    this.sandwich.addIngredient(meat);
  }

  putCheese(cheese) {
    this.sandwich.addIngredient(cheese);
  }

  putVegetables(vegetables) {
    this.sandwich.addIngredient(vegetables);
  }

  get result() {
    return this.sandwich;
  }
}

// 创建用户(director)使用的 builder
class SandwichMaker {
  constructor() {
    this.builder = new SandwichBuilder();
  }

  createCheeseSteakSandwich() {
    this.builder.reset();
    this.builder.putMeat('ribeye steak');
    this.builder.putCheese('american cheese');
    this.builder.putVegetables(['peppers', 'onions']);
    return this.builder.result;
  }
}

// 建造一个三明治
const sandwichMaker = new SandwichMaker();
const sandwich = sandwichMaker.createCheeseSteakSandwich();
console.log(`Your sandwich: ${sandwich}`); // Output: Your sandwich: ribeye steak, american cheese, peppers, onions

原型模式(Prototype Pattern)

原型模式(Prototype Pattern)是一种创建型设计模式,它可以用于创建对象的成本相对较高,但对于由相同属性的对象可以通过克隆来创建。原型模式将对象的创建过程和对象的使用过程分离,它通过克隆已有对象来创建新的对象,从而避免了昂贵的对象创建过程。在 JavaScript 中,原型模式的实现很容易,因为它天然支持对象的 clone(即浅拷贝)。

这是一个使用原型模式的示例代码:

// 创建一个原型对象
const carPrototype = {
  wheels: 4,
  color: 'red',
  start() {
    console.log('Starting the car...');
  },
  stop() {
    console.log('Stopping the car...');
  },
};

// 使用Object.create()方法克隆
const car1 = Object.create(carPrototype);
console.log(car1); // Output: {}

car1.wheels = 6;
console.log(car1.wheels); // Output: 6
console.log(car1.color); // Output: red

car1.start(); // Output: Starting the car...
car1.stop(); // Output: Stopping the car...

// 克隆另一个对象
const car2 = Object.create(carPrototype);
console.log(car2); // Output: {}

car2.color = 'blue'; 
console.log(car2.color); // Output: blue
console.log(car2.wheels); // Output: 4

car2.start(); // Output: Starting the car...
car2.stop(); // Output: Stopping the car...

在这个例子中,我们创建了一个名为 carPrototype 的原型对象。然后,我们通过 Object.create() 方法克隆了该原型对象。由于我们使用了浅拷贝,所以在使用前我们可以修改对象的属性,并且 car2 和 car1 对象的 start() 和 stop() 方法是相同的,因为它们来自相同的原型对象。

原型模式的一个优点是它提供了一种简便的方式来创建具有相同属性的对象。它可以减少重复代码,并且在创建对象时节省时间和资源。当然,它也有一些缺点,例如在使用深拷贝时可能会出现意想不到的问题,因为深拷贝将复制所有属性,而这些属性还可能引用其他对象。

适配器模式(Adapter Pattern)

适配器模式(Adapter Pattern)是一种结构型设计模式,它允许将不兼容的对象包装在适配器中,从而使它们能够在一起工作。以下是适配器模式的代码示例:

// 目标接口
class Target {
  request() {
    console.log('Target: 请求已被调用');
  }
}

// 需要适配的类
class Adaptee {
  specificRequest() {
    console.log('Adaptee 方法已被访问');
  }
}

// 适配器类,将 Adaptee 转换为 Target
class Adapter extends Target {
  constructor(adaptee) {
    super();
    this.adaptee = adaptee;
  }

  request() {
    this.adaptee.specificRequest();
  }
}

// 使用适配器将客户端与 Adaptee 解耦
const client = new Adapter(new Adaptee());
client.request(); // Output: Adaptee 方法已被访问

在上述代码中,我们有一个目标接口 Target 和一个需要适配的类 Adaptee。我们通过创建一个适配器类 Adapter 将 Adaptee 转换为 Target,并使用适配器进行通信的客户端 client 调用 request() 方法,从而实现 Adaptee 的功能。

装饰模式(Decorator Pattern)

装饰模式(Decorator Pattern)是一种结构型设计模式,它允许在不影响其他对象的情况下,动态地将功能添加到对象中。以下是装饰模式的代码示例:

// 抽象组件类
class Component {
  operation() {
    console.log('Component:基础操作');
  }
}

// 具体组件类
class ConcreteComponent extends Component {
  operation() {
    console.log('ConcreteComponent:具体操作');
  }
}

// 抽象装饰器类
class Decorator extends Component {
  constructor(component) {
    super();
    this.component = component;
  }

  operation() {
    this.component.operation();
  }
}

// 具体装饰器类
class ConcreteDecoratorA extends Decorator {
  operation() { 
    super.operation();
    console.log('ConcreteDecoratorA:添加操作'); 
  }
}

class ConcreteDecoratorB extends Decorator {
  operation() { 
    super.operation();
    console.log('ConcreteDecoratorB:添加操作'); 
  }
}

// 使用装饰器组合对象
const component = new ConcreteComponent();
const decoratorA = new ConcreteDecoratorA(component);
const decoratorB = new ConcreteDecoratorB(decoratorA);
decoratorB.operation();

在上述代码中,我们有一个抽象组件类 Component 和一个具体组件类 ConcreteComponent。我们创建了两个装饰器类 ConcreteDecoratorA 和 ConcreteDecoratorB,它们都继承自 Decorator 类,并且可以添加新的行为到被装饰的对象上。最后,我们实例化 ConcreteComponent 类,将其封装在 ConcreteDecoratorA 和 ConcreteDecoratorB 类中,最终组成一个具有多个操作的对象。

代理模式(Proxy Pattern)

代理模式(Proxy Pattern)是一种结构型设计模式,它允许在访问对象时提供一个占位符或代理,以控制对对象的访问。以下是代理模式的代码示例:

// 主题接口
class Subject {
  request() {
    console.log('Subject:处理请求');
  }
}

// 真实主题类
class RealSubject extends Subject {
  request() {
    console.log('RealSubject:处理请求');
  }
}

// 代理类
class Proxy extends Subject {
  constructor(realSubject) {
    super();
    this.realSubject = realSubject;
  }

  request() {
    if (this.checkAccess()) {
      this.realSubject.request();
      this.logAccess();
    }
  }

  checkAccess() {
    console.log('Proxy:检查访问权限');
    return true;
  }

  logAccess() {
    console.log('Proxy:记录访问日志');
  }
}

// 使用代理访问真实对象
const realSubject = new RealSubject();
const proxy = new Proxy(realSubject);

proxy.request();

在上述代码中,我们有一个主题接口 Subject 和一个真实主题类 RealSubject。我们创建了一个代理类 Proxy,它封装了一个真实主题,并在对其进行访问时提供了额外的功能,例如检查访问权限和记录访问日志。我们通过实例化 RealSubject 类并封装它在 Proxy 类中,最终通过代理访问真实的主题对象。

外观模式(Facade Pattern)

外观模式(Facade Pattern)是一种结构型设计模式它为一组复杂的子系统提供了一个更简单的接口。以下是外观模式的代码示例:

// 子系统1
class Subsystem1 {
  operation1() {
    console.log('Subsystem1:执行操作1');
  }
}

// 子系统2
class Subsystem2 {
  operation2() {
    console.log('Subsystem2:执行操作2');
  }
}

// 外观类
class Facade {
  constructor() {
    this.subsystem1 = new Subsystem1();
    this.subsystem2 = new Subsystem2();
  }

  operation() {
    this.subsystem1.operation1();
    this.subsystem2.operation2();
  }
}

// 客户端代码
const facade = new Facade();
facade.operation(); // Output: Subsystem1:执行操作1,Subsystem2:执行操作2

在上述代码中,我们有两个子系统 Subsystem1 和 Subsystem2,它们都提供了复杂的操作。我们通过使用外观模式创建了一个 Facade 类,它的接口更加简单,通过组合 Subsystem1 和 Subsystem2 对象的操作来实现其功能。最后,我们实例化 Facade 类并调用操作方法 operation(),完成了复杂的功能操作。

桥接模式(Bridge Pattern)

桥接模式(Bridge Pattern)是一种结构型设计模式,它将一个对象的抽象和实现分离开来,从而使它们都可以独立变化。以下是桥接模式的示例代码:

// 实现类接口
class Implementor {
  operationImpl() {
    console.log('Implementor:执行操作');
  }
}

// 抽象类
class Abstraction {
  constructor(implementor) {
    this.implementor = implementor;
  }

  operation() {
    this.implementor.operationImpl();
  }
}

// 扩展抽象类
class RefinedAbstraction extends Abstraction {
  otherOperation() {
    console.log('RefinedAbstraction:其他操作');
  }
}

// 使用桥接模式
const implementor = new Implementor();
const abstraction = new Abstraction(implementor);
abstraction.operation(); // Output: Implementor:执行操作

const refinedAbstraction = new RefinedAbstraction(implementor);
refinedAbstraction.operation(); // Output: Implementor:执行操作
refinedAbstraction.otherOperation(); // Output: RefinedAbstraction:其他操作

在上述代码中,我们有一个实现类接口 Implementor 和一个抽象类 Abstraction。我们通过创建一个扩展抽象类 RefinedAbstraction 来扩展抽象类的功能,它们都使用了某个实现类的实例对象。然后,我们实例化 Implementor 并通过在 Abstraction 和 RefinedAbstraction 类的声明中传递 Implementor 对象来创建两个具有不同行为的对象。通过将实现和抽象分离开来,我们可以随意地组合实现与抽象,并使其易于扩展。

组合模式(Composite Pattern)

组合模式(Composite Pattern)是一种结构型设计模式,它使用树形结构来表示对象的部分-整体层次结构,并使用户能够以统一的方式处理单个对象和对象组合。以下是组合模式的示例代码:

// 抽象构件
class Component {
  constructor(name) {
    this.name = name;
  }

  operation() {
    console.log(`Component ${this.name}:执行操作`);
  }

  add(component) {
    console.log('Component:不支持的操作');
  }

  remove(component) {
    console.log('Component:不支持的操作');
  }

  getChild(index) {
    console.log('Component:不支持的操作');
  }
}

// 叶子节点
class Leaf extends Component {
  constructor(name) {
    super(name);
  }
}

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

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

  remove(component) {
    const index = this.children.indexOf(component);
    if (index >= 0) {
      this.children.splice(index, 1);
    }
  }

  getChild(index) {
    return this.children[index];
  }
}

// 使用组合模式
const root = new Composite('根');
const branch1 = new Composite('树枝1');
const branch2 = new Composite('树枝2');
const leaf1 = new Leaf('叶子1');
const leaf2 = new Leaf('叶子2');
const leaf3 = new Leaf('叶子3');

root.add(branch1);
root.add(branch2);
branch1.add(leaf1);
branch1.add(leaf2);
branch2.add(leaf3);

root.operation(); // Output: Component 根:执行操作
branch1.operation(); // Output: Component 树枝1:执行操作

branch1.remove(leaf2);
branch2.operation(); // Output: Component 树枝2:执行操作

root.getChild(0).operation(); // Output: Component 树枝1:执行操作

在上述代码中,我们有一个抽象构件 Component,通过创建两个具体构建 Leaf 和 Composite 来扩展抽象构件的功能。 Composite 保持着一个子对象的数组,并实现了在包含其他组件的能力。然后,我们使用所有这些组件来建立一个树形结构, 父节点模型是 Component 对象,而子节点可以是 Component 对象或 Composite 对象。最终,我们可以通过调用操作方法来进行操作。

享元模式(Flyweight Pattern)

享元模式(Flyweight Pattern)是一种结构型设计模式,它通过共享对象来最小化内存使用和类实例化的数量。以下是享元模式的示例代码:

// Flyweight 工厂类
class FlyweightFactory {
  constructor() {
    this.flyweights = {};
  }

  getFlyweight(key) {
    if (!this.flyweights[key]) {
      this.flyweights[key] = new ConcreteFlyweight(key);
    }

    return this.flyweights[key];
  }
}

// 具体 Flyweight 类
class ConcreteFlyweight {
  constructor(key) {
    this.key = key;
  }

  operation() {
    console.log(`ConcreteFlyweight ${this.key}: 执行操作`);
  }
}

// 使用享元模式
const factory = new FlyweightFactory();
const flyweight1 = factory.getFlyweight('key');
const flyweight2 = factory.getFlyweight('key');
flyweight1.operation(); // Output: ConcreteFlyweight key: 执行操作
flyweight2.operation(); // Output: ConcreteFlyweight key: 执行操作
console.log(flyweight1 === flyweight2); // Output: true

在上述代码中,我们有一个 Flyweight 工厂类 FlyweightFactory,用于创建并管理基础的共享 ConcreteFlyweight 对象。ConcreteFlyweight 对象包含需要共享的数据或状态。我们实例化 FlyweightFactory,并通过在 FlyweightFactory 的 getFlyweight() 方法中获取对象,以及通过多个对象来验证是否共享相同的对象。最终,结果显示 flyweight1 跟 flyweight2 指向同一个对象,由此证明了共享对象的概念。

策略模式(Strategy Pattern)

策略模式是一种设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。策略模式让算法独立于使用它的客户端而独立变化。这种模式属于行为型模式。 示例代码如下:

class Strategy {
  constructor(name) {
    this.name = name;
  }
  
  execute() {}
}

class StrategyA extends Strategy {
  execute() {
    console.log('Executing strategy A');
  }
} 

class StrategyB extends Strategy {
  execute() {
    console.log('Executing strategy B');
  }
}

class Context {
  constructor(strategy) {
    this.strategy = strategy;
  }
  
  executeStrategy() {
    this.strategy.execute();
  }
}

let context = new Context(new StrategyA('A'));
context.executeStrategy(); // Executing strategy A
 
context.strategy = new StrategyB('B');
context.executeStrategy(); // Executing strategy B

模板方法模式(Template Method Pattern)

模板方法模式是一种行为设计模式。它定义了一个操作中的算法骨架,将某些步骤延迟到子类中实现。模板方法使得子类可以不改变算法的结构即可重新定义该算法的某些特定步骤

示例代码:

class Game {
  setup() {}
  
  start() {
    this.setup();
    this.play();
    this.finish();
  }
  
  play() {}
  
  finish() {}
}

class Chess extends Game {
  setup() {
    console.log('Setting up chess game');
  }
  
  play() {
    console.log('Playing chess');
  }
  
  finish() {
    console.log('Finishing chess game');
  }
}

class TicTacToe extends Game {
  setup() {
    console.log('Setting up TicTacToe game');
  }
  
  play() {
    console.log('Playing TicTacToe');
  }
  
  finish() {
    console.log('Finishing TicTacToe game');
  }
}

let game = new Chess();
game.start();

game = new TicTacToe();
game.start();

观察者模式(Observer Pattern)

观察者模式是一种行为设计模式,其中对象之间存在一对多的依赖关系。当一个对象的状态发生变化时,它的所有依赖者都得到通知并自动更新。观察者模式将对象之间的关系解耦,使得它们可以独立变化

示例代码:

class Subject {
  constructor() {
    this.observers = [];
  }
  
  attach(observer) {
    this.observers.push(observer);
  }
  
  detach(observer) {
    const index = this.observers.indexOf(observer);
    if (index > -1) {
      this.observers.splice(index, 1);
    }
  }
  
  notify() {
    for(const observer of this.observers) {
      observer.update(this);
    }
  }
}

class Observer {
  update(subject) {}
}

class ConcreteSubject extends Subject {
  constructor(state) {
    super();
    this.state = state;
  }
  
  set_state(state) {
    this.state = state;
    this.notify();
  }
  
  get_state() {
    return this.state;
  }
} 

class ConcreteObserver extends Observer {
  update(subject) {
    console.log(`Got updated value: ${subject.get_state()}`);
  }
}

let subject = new ConcreteSubject('initial state');
let observer = new ConcreteObserver();

subject.attach(observer);
subject.set_state('new state');

迭代器模式(Iterator Pattern)

迭代器模式是一种行为设计模式,它提供了一种方式来顺序访问集合对象中的元素。迭代器模式将遍历集合的责任交给迭代器,而不是集合自己。这样就可以将集合的实现和遍历算法的实现分离开来,从而提供更好的灵活性。

示例代码:

class Iterator {
  constructor(items) {
    this.items = items;
    this.cursor = 0;
  }
  
  has_next() {
    return this.cursor < this.items.length;
  }
  
  next() {
    const item = this.items[this.cursor];
    this.cursor += 1;
    return item;
  }
}

class Collection {
  constructor() {
    this.items = [];
  }
  
  add_item(item) {
    this.items.push(item);
  }
  
  iterator() {
    return new Iterator(this.items);
  }
}

const collection = new Collection();
collection.add_item('item 1');
collection.add_item('item 2');
collection.add_item('item 3');

const iterator = collection.iterator();
while(iterator.has_next()) {
  console.log(iterator.next());
}

责任链模式(Chain of Responsibility)

责任链模式(Chain of Responsibility)是一种行为型设计模式。它可以让多个对象都有机会处理请求,从而避免将请求的发送者和接收者耦合在一起。将这些对象连成一个链,并沿着这条链传递请求,直到有一个对象处理它为止。

实现方式:

class Handler {
  constructor() {
    this.nextHandler = null;
  }

  setNextHandler(handler){
    this.nextHandler = handler;
  }

  handleRequest(request) {
    if (this.nextHandler !== null) {
      return this.nextHandler.handleRequest(request);
    }
    return null;
  }
}

class ConcreteHandlerA extends Handler {
  handleRequest(request) {
    if (request === 'A') {
      return `Handle Request ${request}`;
    }
    return super.handleRequest(request);
  }
}

class ConcreteHandlerB extends Handler {
  handleRequest(request) {
    if (request === 'B') {
      return `Handle Request ${request}`;
    }
    return super.handleRequest(request);
  }
}

class ConcreteHandlerC extends Handler {
  handleRequest(request) {
    if (request === 'C') {
      return `Handle Request ${request}`;
    }
    return super.handleRequest(request);
  }
}

const handlerA = new ConcreteHandlerA();
const handlerB = new ConcreteHandlerB();
const handlerC = new ConcreteHandlerC();

handlerA.setNextHandler(handlerB);
handlerB.setNextHandler(handlerC);

console.log(handlerA.handleRequest('A')); // Handle Request A
console.log(handlerA.handleRequest('B')); // Handle Request B
console.log(handlerA.handleRequest('C')); // Handle Request C
console.log(handlerA.handleRequest('D')); // null

命令模式(Command)

命令模式(Command)是一种行为型设计模式,它将请求或操作封装到一个对象中,从而允许你将请求或操作的发起者与具体执行者解耦。命令模式可以将请求或操作参数化,甚至在运行时动态地组合命令

实现方式:

class Command {
  constructor(receiver) {
    this.receiver = receiver;
  }

  execute() {
    throw new Error('You have to implement the method execute!');
  }
}

class ConcreteCommandA extends Command {
  execute() {
    this.receiver.actionA();
  }
}

class ConcreteCommandB extends Command {
  execute() {
    this.receiver.actionB();
  }
}

class Receiver {
  actionA() {
    console.log('Receiver Action A.');
  }

  actionB() {
    console.log('Receiver Action B.');
  }
}

class Invoker {
  constructor() {
    this.commands = new Map();
  }

  setCommand(key, command) {
    this.commands.set(key, command);
  }

  executeCommand(key) {
    const command = this.commands.get(key);
    if (!command) {
      console.log(`Command ${key} is not found.`);
      return;
    }
    command.execute();
  }
}

const receiver = new Receiver();
const invoker = new Invoker();

invoker.setCommand('A', new ConcreteCommandA(receiver));
invoker.setCommand('B', new ConcreteCommandB(receiver));

invoker.executeCommand('A'); // Receiver Action A.
invoker.executeCommand('B'); // Receiver Action B.

备忘录模式(Memento)

备忘录模式(Memento)是一种行为型设计模式,它允许你在不暴露对象实现细节的情况下保存和恢复对象的状态。备忘录模式涉及到三个角色:备忘录(Memento), 发起人(Originator), 管理者(Caretaker)

实现方式:

class Memento {
  constructor(state) {
    this.state = state;
  }

  getState() {
    return this.state;
  }
}

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

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

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

  restoreMemento(memento) {
    this.state = memento.getState();
  }

  getState() {
    return this.state;
  }
}

class Caretaker {
  constructor() {
    this.mementos = [];
  }

  addMemento(memento) {
    this.mementos.push(memento);
  }

  getMemento(index) {
    return this.mementos[index];
  }
}

const originator = new Originator('State A');
const caretaker = new Caretaker();

// Save state
caretaker.addMemento(originator.createMemento());

// change state
originator.setState('State B');

console.log(`Current State: ${originator.getState()}`);

// Restore state
originator.restoreMemento(caretaker.getMemento(0));

console.log(`Current State: ${originator.getState()}`);

状态模式(State)

状态模式(State)是一种行为型设计模式,它允许对象在其内部状态发生改变时改变其行为。状态模式通过将每个状态封装在一个类中,使得对于该状态进行的任何操作都可以在该类中处理。从而将状态转换的代码从主要业务逻辑中抽离出来,避免出现大量 if-else 语句

实现方式:

class Context {
  constructor() {
    this.state = new ConcreteStateA(this);
  }

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

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

class State {
  constructor(context) {
    this.context = context;
  }

  handle() {
    throw new Error('You have to implement the method handle!');
  }
}

class ConcreteStateA extends State {
  handle() {
    console.log('Handle State A');
    this.context.setState(new ConcreteStateB(this.context));
  }
}

class ConcreteStateB extends State {
  handle() {
    console.log('Handle State B');
    this.context.setState(new ConcreteStateA(this.context));
  }
}

const context = new Context();
context.request(); // Handle State A
context.request(); // Handle State B
context.request(); // Handle State A

访问者模式(Visitor)

访问者模式(Visitor)是一种行为型设计模式,它允许你将算法封装在一个或多个访问者类中,从而让你在不改变各个元素类接口的前提下定义作用于这些元素的新操作

实现方式:

class Element {
  accept(visitor) {
    throw new Error('You have to implement the method accept!');
  }
}

class ConcreteElementA extends Element {
  accept(visitor) {
    visitor.visitConcreteElementA(this);
  }

  operationA() {
    console.log('Operation A of Concrete Element A.');
  }
}

class ConcreteElementB extends Element {
  accept(visitor) {
    visitor.visitConcreteElementB(this);
  }

  operationB() {
    console.log('Operation B of Concrete Element B.');
  }
}

class Visitor {
  visitConcreteElementA(element) {
    console.log(`Visit Concrete Element A with ${element.operationA()}`);
  }

  visitConcreteElementB(element) {
    console.log(`Visit Concrete Element B with ${element.operationB()}`);
  }
}

const elementA = new ConcreteElementA();
const elementB = new ConcreteElementB();
const visitor = new Visitor();

elementA.accept(visitor);
elementB.accept(visitor);

中介者模式(Mediator)

中介者模式(Mediator)是一种行为型设计模式,它允许你减少组件之间的直接依赖关系,将它们通过一个中介者对象进行交互。通过避免在组件之间显式引用彼此,中介者可以让你更容易地复用组件。

实现方式:

class Mediator {
  constructor() {
    this.components = new Set();
  }

  register(component) {
    component.mediator = this;
    this.components.add(component);
  }

  notify(sender, event) {
    this.components.forEach((component) => {
      if (component !== sender) {
        component.receive(sender, event);
      }
    });
  }
}

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

  send(event) {
    console.log(`Send event ${event} from ${this.name}`);
    this.mediator.notify(this, event);
  }

  receive(sender, event) {
    console.log(`Receive event ${event} from ${sender.name} by ${this.name}`);
  }
}

const mediator = new Mediator();
const componentA = new Component('Component A');
const componentB = new Component('Component B');
const componentC = new Component('Component C');
mediator.register(componentA);
mediator.register(componentB);
mediator.register(componentC);

componentA.send('Hello');  //Send event Hello from Component A, Receive event Hello from Component A by Component B, Receive event Hello from Component A by Component C

解释器模式(Interpreter)

解释器模式(Interpreter)是一种行为型设计模式,它能够将一种语言(通常是一种编程语言)或者表达式的文法表示为解析树,并定义一个解释器,使用该解释器来解释这个语言或者表达式

实现方式:

class Context {
  constructor(input) {
    this.input = input;
    this.output = 0;
  }
}

class Expression {
  interpreter(context) {
    throw new Error('You have to implement the method interpreter!');
  }
}

class ThousandExpression extends Expression {
  interpreter(context) {
    const str = context.input;
    if (str.startsWith('M')) {
      context.output += 1000;
      context.input = str.slice(1);
    }
  }
}

class HundredExpression extends Expression {
  interpreter(context) {
    const str = context.input;
    if (str.startsWith('C')) {
      context.output += 100;
      context.input = str.slice(1);
    } else if (str.startsWith('CD')) {
      context.output += 400;
      context.input = str.slice(2);
    } else if (str.startsWith('CM')) {
      context.output += 900;
      context.input = str.slice(2);
    }
  }
}

class TenExpression extends Expression {
  interpreter(context) {
    const str = context.input;
    if (str.startsWith('X')) {
      context.output += 10;
      context.input = str.slice(1);
    } else if (str.startsWith('XL')) {
      context.output += 40;
      context.input = str.slice(2);
    } else if (str.startsWith('XC')) {
      context.output += 90;
      context.input = str.slice(2);
    }
  }
}

class OneExpression extends Expression {
  interpreter(context) {
    const str = context.input;
    if (str.startsWith('I')) {
      context.output += 1;
      context.input = str.slice(1);
    } else if (str.startsWith('IV')) {
      context.output += 4;
      context.input = str.slice(2);
    } else if (str.startsWith('V')) {
      context.output += 5;
      context.input = str.slice(1);
    } else if (str.startsWith('IX')) {
      context.output += 9;
      context.input = str.slice(2);
    }
  }
}

class Interpreter {
  static parse(roman) {
    const context = new Context(roman);
    const tree = [
      new ThousandExpression(),
      new HundredExpression(),
      new TenExpression(),
      new OneExpression(),
    ];
    tree.forEach((expression) => expression.interpreter(context));
    return context.output;
  }
}

console.log(Interpreter.parse('CDXLVIII')); // 448

总结

现在你已经掌握了这些设计模式,是时候让你的代码从“我不知道这是什么”变成“这是我写的,我知道它是什么了”了!快去展示你的新技能吧,让你的同事们惊叹不已!