设计模式

单例模式

单例模式确保一个类只有一个实例,并提供一个全局访问点

class Singleton {
  constructor(name) {
    if (!Singleton.instance) {
      this.name = name;
      Singleton.instance = this;
    }
    return Singleton.instance;
  }

  static getInstance(name) {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton(name);
    }
    return Singleton.instance;
  }

  sayHello() {
    console.log(`Hello, I am ${this.name}`);
  }
}

const instance1 = Singleton.getInstance("Instance 1");
const instance2 = Singleton.getInstance("Instance 2");

instance1.sayHello(); // Hello, I am Instance 1
instance2.sayHello(); // Hello, I am Instance 1

实际使用案例

假设我们有一个前端项目,需要在多个组件之间共享一些全局配置(如 API 基础 URL、用户信息等)。我们可以使用单例模式来管理这些配置

class ConfigManager {
  constructor() {
    if (!ConfigManager.instance) {
      this.config = {
        apiUrl: "https://api.example.com",
        userId: null,
        // 其他配置项
        isLoggedIn: false, // 登录状态
        cartItems: [], // 购物车商品
      };
      ConfigManager.instance = this;
    }
    return ConfigManager.instance;
  }

  static getInstance() {
    if (!ConfigManager.instance) {
      ConfigManager.instance = new ConfigManager();
    }
    return ConfigManager.instance;
  }

  setConfig(key, value) {
    this.config[key] = value;
  }

  getConfig(key) {
    return this.config[key];
  }
}
  1. 在项目启动时,可以初始化配置
    import { ConfigManager } from "./ConfigManager";
    
    const configManager = ConfigManager.getInstance();
    
    configManager.setConfig("userId", "12345");
    
    //在需要访问配置的组件中,可以获取 ConfigManager 的实例并使用配置
    import React, { useEffect } from "react";
    import { ConfigManager } from "./ConfigManager";
    
    function MyComponent() {
      const configManager = ConfigManager.getInstance();
    
      useEffect(() => {
        const apiUrl = configManager.getConfig("apiUrl");
        const userId = configManager.getConfig("userId");
    
        console.log("API URL:", apiUrl);
        console.log("User ID:", userId);
    
        // 使用配置进行数据请求等操作
      }, []);
    
      return (
        <div>
          <p>API URL: {configManager.getConfig("apiUrl")}</p >
          <p>User ID: {configManager.getConfig("userId")}</p >
        </div>
      );
    }
    
     export default MyComponent;

工厂模式

工厂模式用于创建对象,而无需指定具体的类,它将创建对象的逻辑封装在工厂函数中

class Car {
  constructor(model) {
    this.model = model;
  }

  drive() {
    console.log(`Driving ${this.model}`);
  }
}

class Factory {
  static createCar(model) {
    return new Car(model);
  }
}

const car1 = Factory.createCar("Toyota");
car1.drive(); // Driving Toyota

const car2 = Factory.createCar("Honda");
car2.drive(); // Driving Honda

动态创建表单组件

假设我们有一个前端项目,需要根据不同的表单类型动态创建相应的表单组件。我们可以使用工厂模式来实现这一点

  1. 定义不同类型的表单组件
    class TextInput {
      constructor(label, name) {
        this.label = label;
        this.name = name;
      }
    
      render() {
        return `<label>${this.label}: <input type="text" name="${this.name}" /></label>`;
      }
    }
    
    class CheckboxInput {
      constructor(label, name) {
        this.label = label;
        this.name = name;
      }
    
      render() {
        return `<label><input type="checkbox" name="${this.name}" /> ${this.label}</label>`;
      }
    }
    
    class SelectInput {
      constructor(label, name, options) {
        this.label = label;
        this.name = name;
        this.options = options;
      }
    
      render() {
        const optionsHtml = this.options
          .map(
            (option) => `<option value="${option.value}">${option.label}</option>`
          )
          .join("");
        return `<label>${this.label}: <select name="${this.name}">${optionsHtml}</select></label>`;
      }
    }
  2. 接下来,我们创建一个工厂类 FormFactory,用于根据表单类型创建相应的组件实例
    class FormFactory {
      static createInput(type, label, name, options = []) {
        switch (type) {
          case "text":
            return new TextInput(label, name);
          case "checkbox":
            return new CheckboxInput(label, name);
          case "select":
            return new SelectInput(label, name, options);
          default:
            throw new Error("Unknown input type");
        }
      }
    }
  3. 在项目中使用 FormFactory 类来动态创建表单组件
    import React, { useEffect, useState } from "react";
    import { FormFactory } from "./FormFactory";
    
    function DynamicForm() {
      const [formInputs, setFormInputs] = useState([]);
    
      useEffect(() => {
        // 定义表单配置
        const formConfig = [
          { type: "text", label: "Name", name: "name" },
          { type: "checkbox", label: "Accept Terms", name: "accept_terms" },
          {
            type: "select",
            label: "Country",
            name: "country",
            options: [
              { value: "us", label: "United States" },
              { value: "uk", label: "United Kingdom" },
              { value: "ca", label: "Canada" },
            ],
          },
        ];
    
        // 使用工厂类创建表单组件
        const inputs = formConfig.map((config) =>
          FormFactory.createInput(
            config.type,
            config.label,
            config.name,
            config.options
          )
        );
        setFormInputs(inputs);
      }, []);
    
      return (
        <form>
          {formInputs.map((input, index) => (
            <div key={index} dangerouslySetInnerHTML={{ __html: input.render() }} />
          ))}
          <button type="submit">Submit</button>
        </form>
      );
    }
    
     export default DynamicForm;

    抽象工厂模式

    抽象工厂模式提供一个接口,用于创建一系列相关的对象,而无需指定具体的类
class AbstractFactory {
  createCar() {}
  createBike() {}
}

class ToyotaFactory extends AbstractFactory {
  createCar() {
    return new Car("Toyota");
  }

  createBike() {
    return new Bike("Toyota");
  }
}

class HondaFactory extends AbstractFactory {
  createCar() {
    return new Car("Honda");
  }

  createBike() {
    return new Bike("Honda");
  }
}

class Car {
  constructor(model) {
    this.model = model;
  }

  drive() {
    console.log(`Driving ${this.model}`);
  }
}

class Bike {
  constructor(model) {
    this.model = model;
  }

  ride() {
    console.log(`Riding ${this.model}`);
  }
}

const toyotaFactory = new ToyotaFactory();
const toyotaCar = toyotaFactory.createCar();
toyotaCar.drive(); // Driving Toyota

const hondaFactory = new HondaFactory();
const hondaBike = hondaFactory.createBike();
hondaBike.ride(); // Riding Honda

创建不同品牌的汽车和自行车

假设我们有一个前端项目,需要根据不同的品牌创建相应的汽车和自行车。我们可以使用抽象工厂模式来实现这一点

  1. 首先,我们定义汽车和自行车的产品接口
    class Car {
      constructor(model) {
        this.model = model;
      }
    
      drive() {
        console.log(`Driving ${this.model}`);
      }
    }
    
    class Bike {
      constructor(model) {
        this.model = model;
      }
    
      ride() {
        console.log(`Riding ${this.model}`);
      }
    }
    
  2. 接下来,我们定义一个抽象工厂接口 AbstractFactory,用于创建汽车和自行车
    class AbstractFactory {
      createCar() {}
      createBike() {}
    }
    
  3. 然后,我们创建两个具体工厂类 ToyotaFactory 和 HondaFactory,分别用于创建丰田和本田品牌的汽车和自行车
    class ToyotaFactory extends AbstractFactory {
      createCar() {
        return new Car("Toyota Camry");
      }
    
      createBike() {
        return new Bike("Toyota Cruiser");
      }
    }
    
    class HondaFactory extends AbstractFactory {
      createCar() {
        return new Car("Honda Civic");
      }
    
      createBike() {
        return new Bike("Honda Rebel");
      }
    }
    
  4. 项目中使用具体工厂类来创建不同品牌的汽车和自行车
    import React, { useEffect, useState } from "react";
    import { ToyotaFactory, HondaFactory } from "./factories";
    
    function VehicleShowcase() {
      const [cars, setCars] = useState([]);
      const [bikes, setBikes] = useState([]);
    
      useEffect(() => {
        // 使用 ToyotaFactory 创建丰田品牌的汽车和自行车
        const toyotaFactory = new ToyotaFactory();
        const toyotaCar = toyotaFactory.createCar();
        const toyotaBike = toyotaFactory.createBike();
        setCars([...cars, toyotaCar]);
        setBikes([...bikes, toyotaBike]);
    
        // 使用 HondaFactory 创建本田品牌的汽车和自行车
        const hondaFactory = new HondaFactory();
        const hondaCar = hondaFactory.createCar();
        const hondaBike = hondaFactory.createBike();
        setCars([...cars, hondaCar]);
        setBikes([...bikes, hondaBike]);
      }, []);
    
      return (
        <div>
          <h2>Cars</h2>
          <ul>
            {cars.map((car, index) => (
              <li key={index}>
                {car.model}
                <button onClick={() => car.drive()}>Drive</button>
              </li>
            ))}
          </ul>
    
          <h2>Bikes</h2>
          <ul>
            {bikes.map((bike, index) => (
              <li key={index}>
                {bike.model}
                <button onClick={() => bike.ride()}>Ride</button>
              </li>
            ))}
          </ul>
        </div>
      );
    }
    
     export default VehicleShowcase;

    原型模式

    原型模式通过复制一个现有对象来创建新对象
    function Car(model) {
      this.model = model;
    }
    
    Car.prototype.drive = function () {
      console.log(`Driving ${this.model}`);
    };
    
    function createCarFromPrototype(model) {
      const car = Object.create(Car.prototype);
      car.model = model;
      return car;
    }
    
    const car3 = createCarFromPrototype("Toyota");
    car3.drive(); // Driving Toyota
    
    const car4 = createCarFromPrototype("Honda");
    car4.drive(); // Driving Honda

创建和管理任务

假设我们有一个前端项目,需要创建和管理多个任务对象。每个任务对象都有相似的属性和方法,但具体的值可能不同。我们可以使用原型模式来实现这一点

  1. 首先,我们定义一个任务原型对象 TaskPrototype,包含任务的基本属性和方法
    function TaskPrototype(title, description, dueDate) {
      this.title = title;
      this.description = description;
      this.dueDate = dueDate;
      this.completed = false;
    }
    
    TaskPrototype.prototype.complete = function () {
      this.completed = true;
      console.log(`${this.title} completed`);
    };
    
    TaskPrototype.prototype.display = function () {
      console.log(`Title: ${this.title}`);
      console.log(`Description: ${this.description}`);
      console.log(`Due Date: ${this.dueDate}`);
      console.log(`Completed: ${this.completed ? "Yes" : "No"}`);
    };
  2. 接下来,我们使用 Object.create 方法来创建具体的任务对象,并根据需要设置不同的属性值
    const taskPrototype = new TaskPrototype();
    
    function createTask(title, description, dueDate) {
      const task = Object.create(taskPrototype);
      task.title = title;
      task.description = description;
      task.dueDate = dueDate;
      return task;
    }
    
  3. 在项目中使用创建的任务对象,调用它们的方法
    import React, { useEffect, useState } from "react";
    import { createTask } from "./tasks";
    
    function TaskManager() {
      const [tasks, setTasks] = useState([]);
    
      useEffect(() => {
        const task1 = createTask(
          "Buy groceries",
          "Go to the supermarket and buy fruits and vegetables",
          "2023-10-01"
        );
        const task2 = createTask(
          "Write report",
          "Complete the project report by the deadline",
          "2023-10-15"
        );
        setTasks([task1, task2]);
      }, []);
    
      const handleComplete = (task) => {
        task.complete();
        setTasks([...tasks]);
      };
    
      return (
        <div>
          <h2>Tasks</h2>
          <ul>
            {tasks.map((task, index) => (
              <li key={index}>
                {task.title}
                <button onClick={() => handleComplete(task)}>Complete</button>
              </li>
            ))}
          </ul>
        </div>
      );
    }
    
     export default TaskManager;

观察者模式

观察者模式定义了对象之间的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新

class Subject {
  constructor() {
    this.observers = [];
  }

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

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

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

class Observer {
  update() {
    console.log("Observer updated");
  }
}

const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();

subject.addObserver(observer1);
subject.addObserver(observer2);

subject.notify(); // Observer updated (两次)

在多个组件中使用观察者模式

假设我们有多个组件需要接收通知,可以将主题实例作为上下文提供给这些组件

  1. 首先,我们创建一个 React 上下文来提供主题实例
    import React, { createContext, useContext } from "react";
    import { Subject } from "./observer";
    
    const NotificationContext = createContext();
    
    function NotificationProvider({ children }) {
      const subject = new Subject();
    
      return (
        <NotificationContext.Provider value={subject}>
          {children}
        </NotificationContext.Provider>
      );
    }
    
    export { NotificationProvider, NotificationContext };
  2. 在需要接收通知的组件中使用上下文来获取主题实例,并注册为观察者
    import React, { useEffect } from "react";
    import { useContext } from "react";
    import { NotificationContext } from "./NotificationProvider";
    
    function ObserverComponent({ name }) {
      const subject = useContext(NotificationContext);
    
      useEffect(() => {
        const observer = new Observer(name);
        subject.addObserver(observer);
    
        return () => {
          subject.removeObserver(observer);
        };
      }, [subject, name]);
    
      return (
        <div>
          <h3>{name}</h3>
          <p>Waiting for notifications...</p >
        </div>
      );
    }
    
     export default ObserverComponent;
  3. 在应用的入口文件中,使用 NotificationProvider 包裹组件树,以便所有子组件都可以访问主题实例
    import React from "react";
    import ReactDOM from "react-dom";
    import { NotificationProvider } from "./NotificationProvider";
    import App from "./App";
    
    ReactDOM.render(
      <NotificationProvider>
        <App />
      </NotificationProvider>,
      document.getElementById("root")
    );
    

装饰器模式

装饰器模式允许动态地给对象添加职责,而不改变其接口

class Car {
  drive() {
    console.log("Driving");
  }
}

class CarDecorator {
  constructor(car) {
    this.car = car;
  }

  drive() {
    this.car.drive();
  }

  startEngine() {
    console.log("Starting engine");
  }
}

const car = new Car();
const decoratedCar = new CarDecorator(car);

decoratedCar.drive(); // Driving
decoratedCar.startEngine(); // Starting engine

扩展按钮组件

假设我们有一个前端项目,需要创建一个基础的按钮组件,并根据不同的需求扩展其功能。我们可以使用装饰器模式来实现这一点

  1. 首先,我们定义一个基础的按钮组件
    class Button {
      constructor(text) {
        this.text = text;
      }
      render() {
        return `<button>${this.text}</button>`;
      }
    }
  2. 接下来,我们定义几个装饰器类来扩展按钮组件的功能。例如,添加点击事件和样式
    class ClickableButton {
      constructor(button) {
        this.button = button;
      }
    
      render() {
        const buttonHtml = this.button.render();
        return `<div onclick="alert('Button clicked!')">${buttonHtml}</div>`;
      }
    }
    
    class StyledButton {
      constructor(button) {
        this.button = button;
      }
    
      render() {
        const buttonHtml = this.button.render();
        return `<div style="background-color: lightblue; padding: 10px;">${buttonHtml}</div>`;
      }
    }
    
  3. 在项目中使用装饰器类来扩展按钮组件的功能
    import React, { useEffect, useState } from "react";
    import { Button, ClickableButton, StyledButton } from "./components";
    
    function App() {
      const [button, setButton] = useState(new Button("Click me"));
    
      useEffect(() => {
        // 使用装饰器扩展按钮功能
        const clickableButton = new ClickableButton(button);
        const styledClickableButton = new StyledButton(clickableButton);
    
        setButton(styledClickableButton);
      }, []);
    
      return <div dangerouslySetInnerHTML={{ __html: button.render() }} />;
    }
    
     export default App;

    策略模式

    策略模式定义了一系列算法,并将每个算法封装起来,使它们可以互换
    
    class Context {
      constructor(strategy) {
        this.strategy = strategy;
      }
    
      setStrategy(strategy) {
        this.strategy = strategy;
      }
    
      execute() {
        this.strategy.execute();
      }
    }
    
    class StrategyA {
      execute() {
        console.log("Executing Strategy A");
      }
    }
    
    class StrategyB {
      execute() {
        console.log("Executing Strategy B");
      }
    }
    
    const context = new Context(new StrategyA());
    context.execute(); // Executing Strategy A
    
    context.setStrategy(new StrategyB());
    context.execute(); // Executing Strategy B

    订单处理系统

    假设我们有一个前端项目,需要根据不同的订单类型选择不同的处理策略。我们可以使用策略模式来实现这一点
  4. 首先,我们定义一个策略接口 OrderStrategy,用于定义订单处理的基本方法
    class OrderStrategy {
      processOrder(order) {
        throw new Error('Method "processOrder" must be implemented.');
      }
    }
  5. 接下来,我们创建几个具体策略类,分别实现不同的订单处理逻辑
    class StandardOrderStrategy extends OrderStrategy {
      processOrder(order) {
        console.log(`Processing standard order: ${order.id}`);
        // 标准订单处理逻辑
      }
    }
    
    class ExpressOrderStrategy extends OrderStrategy {
      processOrder(order) {
        console.log(`Processing express order: ${order.id}`);
        // 快速订单处理逻辑
      }
    }
    
    class SpecialOrderStrategy extends OrderStrategy {
      processOrder(order) {
        console.log(`Processing special order: ${order.id}`);
        // 特殊订单处理逻辑
      }
    }
  6. 然后,我们创建一个上下文类 OrderContext,用于根据订单类型选择并执行相应的策略
    class OrderContext {
      constructor(strategy) {
        this.strategy = strategy;
      }
    
      setStrategy(strategy) {
        this.strategy = strategy;
      }
    
      processOrder(order) {
        this.strategy.processOrder(order);
      }
    }
  7. 在项目中使用策略模式来处理不同类型的订单
    import React, { useEffect } from "react";
    import {
      StandardOrderStrategy,
      ExpressOrderStrategy,
      SpecialOrderStrategy,
      OrderContext,
    } from "./order";
    
    function OrderSystem() {
      useEffect(() => {
        const standardStrategy = new StandardOrderStrategy();
        const expressStrategy = new ExpressOrderStrategy();
        const specialStrategy = new SpecialOrderStrategy();
    
        const orderContext = new OrderContext(standardStrategy);
    
        const orders = [
          { id: 1, type: "standard" },
          { id: 2, type: "express" },
          { id: 3, type: "special" },
        ];
    
        orders.forEach((order) => {
          switch (order.type) {
            case "standard":
              orderContext.setStrategy(standardStrategy);
              break;
            case "express":
              orderContext.setStrategy(expressStrategy);
              break;
            case "special":
              orderContext.setStrategy(specialStrategy);
              break;
            default:
              throw new Error("Unknown order type");
          }
    
          orderContext.processOrder(order);
        });
      }, []);
    
      return (
        <div>
          <h2>Order System</h2>
          <p>Orders will be processed using different strategies.</p >
        </div>
      );
    }
    
     export default OrderSystem;

    命令模式

    命令模式将请求封装成对象,从而使你可以用不同的请求对客户进行参数化
    class Light {
      turnOn() {
        console.log("Light turned on");
      }
    
      turnOff() {
        console.log("Light turned off");
      }
    }
    
    class Command {
      execute() {}
    }
    
    class TurnOnCommand extends Command {
      constructor(light) {
        super();
        this.light = light;
      }
    
      execute() {
        this.light.turnOn();
      }
    }
    
    class TurnOffCommand extends Command {
      constructor(light) {
        super();
        this.light = light;
      }
    
      execute() {
        this.light.turnOff();
      }
    }
    
    class RemoteControl {
      constructor() {
        this.commands = [];
      }
    
      setCommand(command) {
        this.commands.push(command);
      }
    
      executeCommands() {
        this.commands.forEach((command) => command.execute());
      }
    }
    
    const light = new Light();
    const remote = new RemoteControl();
    
    remote.setCommand(new TurnOnCommand(light));
    remote.setCommand(new TurnOffCommand(light));
    
    remote.executeCommands(); // Light turned on, Light turned off

    文本编辑器

    假设我们有一个前端项目,需要实现一个文本编辑器,支持多种操作(如插入文本、删除文本等)。我们可以使用命令模式来封装这些操作
  8. 首先,我们定义一个命令接口 Command,用于定义命令的基本方法
    class Command {
      execute() {
        throw new Error('Method "execute" must be implemented.');
      }
    
      undo() {
        throw new Error('Method "undo" must be implemented.');
      }
    }
  9. 接下来,我们创建几个具体命令类,分别实现不同的编辑操作
    class InsertTextCommand extends Command {
      constructor(editor, text, position) {
        super();
        this.editor = editor;
        this.text = text;
        this.position = position;
      }
    
      execute() {
        this.editor.insertText(this.text, this.position);
      }
    
      undo() {
        this.editor.deleteText(this.position, this.text.length);
      }
    }
    
    class DeleteTextCommand extends Command {
      constructor(editor, position, length) {
        super();
        this.editor = editor;
        this.position = position;
        this.length = length;
      }
    
      execute() {
        this.editor.deleteText(this.position, this.length);
      }
    
      undo() {
        this.editor.insertText(this.text, this.position);
      }
    }
    
    class UndoCommand extends Command {
      constructor(editor) {
        super();
        this.editor = editor;
      }
    
      execute() {
        this.editor.undo();
      }
    
      undo() {
        // Undo command cannot be undone
      }
    }
  10. 然后,我们创建一个编辑器类 Editor,用于管理文本和执行命令
    class Editor {
      constructor() {
        this.text = "";
        this.history = [];
        this.currentStep = -1;
      }
    
      insertText(text, position) {
        this.text = this.text.slice(0, position) + text + this.text.slice(position);
        this._saveStep();
      }
    
      deleteText(position, length) {
        this.text =
          this.text.slice(0, position) + this.text.slice(position + length);
        this._saveStep();
      }
    
      undo() {
        if (this.currentStep >= 0) {
          const command = this.history[this.currentStep];
          command.undo();
          this.currentStep--;
        }
      }
    
      _saveStep() {
        if (this.currentStep < this.history.length - 1) {
          this.history = this.history.slice(0, this.currentStep + 1);
        }
        this.history.push(new UndoCommand(this));
        this.currentStep++;
      }
    
      getText() {
        return this.text;
      }
    }
  11. 在项目中使用命令模式来执行编辑操作
    import React, { useState } from "react";
    import {
      Editor,
      InsertTextCommand,
      DeleteTextCommand,
      UndoCommand,
    } from "./editor";
    
    function TextEditor() {
      const [text, setText] = useState("");
      const editor = new Editor();
    
      const handleInsert = () => {
        const command = new InsertTextCommand(editor, "Hello", 0);
        command.execute();
        setText(editor.getText());
      };
    
      const handleDelete = () => {
        const command = new DeleteTextCommand(editor, 0, 5);
        command.execute();
        setText(editor.getText());
      };
    
      const handleUndo = () => {
        const command = new UndoCommand(editor);
        command.execute();
        setText(editor.getText());
      };
    
      return (
        <div>
          <h2>Text Editor</h2>
          <textarea value={text} readOnly />
          <div>
            <button onClick={handleInsert}>Insert Text</button>
            <button onClick={handleDelete}>Delete Text</button>
            <button onClick={handleUndo}>Undo</button>
          </div>
        </div>
      );
    }
    
     export default TextEditor;

发布订阅者模式

定义一个事件中心类 EventCenter

class EventCenter {
  constructor() {
    this.events = {}; // 保存所有事件和订阅者
  }

  // 订阅事件
  subscribe(eventName, subscriber) {
    if (!this.events[eventName]) {
      this.events[eventName] = []; // 如果事件不存在,创建一个新的数组
    }
    this.events[eventName].push(subscriber); // 添加订阅者到事件列表中
  }

  // 发布事件
  publish(eventName, data) {
    const subscribers = this.events[eventName] || [];
    for (const subscriber of subscribers) {
      subscriber(data); // 依次执行所有订阅者的回调函数
    }
  }

  clearSubscribe(eventName) {
    let object = {};
    for (const key in this.events) {
      if (key !== eventName) {
        object[key] = this.events[key];
      }
    }
    this.events = object;
  }

  get() {
    console.log(this.events);
  }
}

// 创建一个事件中心对象
const eventCenter = new EventCenter();

// 订阅事件
eventCenter.subscribe("event1", function (data) {
  console.log(`Event1 received data: ${data}`);
});

eventCenter.subscribe("event2", function (data) {
  console.log(`Event2 received data: ${data}`);
});

// 发布事件
eventCenter.publish("event1", "Hello, event1!");
eventCenter.publish("event2", "Hello, event2!");
eventCenter.clearSubscribe("event1");
eventCenter.get();

消息通知系统

假设我们有一个前端项目,需要在用户执行某些操作时向多个组件发送通知。我们可以使用发布订阅者模式来实现这一点

  1. 首先,我们定义一个发布订阅者类 EventBus,用于管理事件的发布和订阅
    class EventBus {
      constructor() {
        this.events = {};
      }
    
      subscribe(eventName, callback) {
        if (!this.events[eventName]) {
          this.events[eventName] = [];
        }
        this.events[eventName].push(callback);
      }
    
      publish(eventName, data) {
        const callbacks = this.events[eventName];
        if (callbacks) {
          callbacks.forEach((callback) => callback(data));
        }
      }
    
      unsubscribe(eventName, callback) {
        const callbacks = this.events[eventName];
        if (callbacks) {
          this.events[eventName] = callbacks.filter((cb) => cb !== callback);
        }
      }
    }
  2. 接下来,我们创建一个 EventBus 实例,并在需要的地方使用它
    const eventBus = new EventBus();
  3. 在需要接收通知的组件中订阅事件,并提供回调函数来处理通知
    import React, { useEffect } from "react";
    // import { eventBus } from "./eventBus";
    
    function NotificationComponent() {
      useEffect(() => {
        const handleNotification = (message) => {
          console.log(`Received notification: ${message}`);
        };
    
        eventBus.subscribe("notification", handleNotification);
    
        // 清理订阅
        return () => {
          eventBus.unsubscribe("notification", handleNotification);
        };
      }, []);
    
      return (
        <div>
          <h3>Notification Component</h3>
          <p>Waiting for notifications...</p >
        </div>
      );
    }
    
     export default NotificationComponent;
  4. 在需要发送通知的地方发布事件
    import React, { useState } from "react";
    import { eventBus } from "./eventBus";
    
    function NotificationSender() {
      const [message, setMessage] = useState("");
    
      const handleSendNotification = () => {
        eventBus.publish("notification", message);
      };
    
      return (
        <div>
          <h3>Notification Sender</h3>
          <input
            type="text"
            value={message}
            onChange={(e) => setMessage(e.target.value)}
            placeholder="Enter notification message"
          />
          <button onClick={handleSendNotification}>Send Notification</button>
        </div>
      );
    }
    
     export default NotificationSender;
  5. 在应用的入口文件中,将 NotificationComponent 和 NotificationSender 组件组合在一起
    import React from "react";
    import ReactDOM from "react-dom";
    import NotificationComponent from "./NotificationComponent";
    import NotificationSender from "./NotificationSender";
    
    function App() {
      return (
        <div>
          <NotificationComponent />
          <NotificationSender />
        </div>
      );
    }
    
    ReactDOM.render(<App />, document.getElementById("root"));