You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

JavaScript中回调模式实现与封装问题求助

解决方案:给SerialPortController添加回调/事件机制实现模块通信

我明白你现在的困境——代码模块化的时候,串口模块和上层应用模块之间没法顺畅通信是吧?其实核心就是你说的,SerialPortController不知道要把数据传给创建它的AppController。下面给你两种简单实用的解决方案,直接套你的代码结构就行:

方案一:回调函数模式(适合单一处理逻辑的场景)

这个方案最简单直接,就是在SerialPortController的构造函数里接收一个回调函数,当串口收到数据时,调用这个回调把数据传递给AppController。

修改后的SerialPortController

class SerialPortController {
  // 构造函数新增回调参数,接收上层的处理函数
  constructor(onDataReceived) {
    this.onDataReceived = onDataReceived;
    // 这里是你的串口初始化逻辑,我用模拟数据代替
    this.startListening();
  }

  sendData(data) {
    // 你的串口发送逻辑
    console.log(`串口发送: ${data}`);
  }

  // 内部收数方法,现在改为触发回调
  dataReceived(data) {
    console.log(`串口原始数据: ${data}`);
    // 如果上层传了回调,就调用它
    if (typeof this.onDataReceived === 'function') {
      this.onDataReceived(data);
    }
  }

  // 模拟串口持续发数据,实际是你的串口监听逻辑
  startListening() {
    setInterval(() => {
      this.dataReceived(`测试数据 ${Date.now()}`);
    }, 2000);
  }
}

修改后的AppController(IIFE模块)

const AppController = (() => {
  function init() {
    // 实例化串口控制器时,传入我们自己的处理函数
    const serialPort = new SerialPortController((data) => {
      handleSerialData(data);
    });

    // 测试发送数据
    serialPort.sendData('请求设备状态');
  }

  // AppController自己的收数处理逻辑
  function handleSerialData(data) {
    console.log(`AppController处理数据: ${data}`);
    // 这里可以加你的业务逻辑,比如更新UI、解析协议等
  }

  return {
    init: init
  };
})();

// 启动应用
AppController.init();

方案二:事件发射器模式(适合多场景监听的扩展性方案)

如果之后你需要在多个地方监听串口数据,事件模式会更灵活。我们给SerialPortController实现一个简单的事件订阅/发布功能,让上层可以订阅特定事件来接收数据。

修改后的SerialPortController

class SerialPortController {
  constructor() {
    // 存储事件监听者
    this.eventListeners = {};
    this.startListening();
  }

  sendData(data) {
    console.log(`串口发送: ${data}`);
  }

  dataReceived(data) {
    console.log(`串口原始数据: ${data}`);
    // 触发'data'事件,通知所有订阅者
    this.emit('data', data);
  }

  // 订阅事件的方法
  on(eventName, callback) {
    if (!this.eventListeners[eventName]) {
      this.eventListeners[eventName] = [];
    }
    this.eventListeners[eventName].push(callback);
  }

  // 发布事件的方法
  emit(eventName, payload) {
    if (this.eventListeners[eventName]) {
      this.eventListeners[eventName].forEach(callback => callback(payload));
    }
  }

  startListening() {
    setInterval(() => {
      this.dataReceived(`测试数据 ${Date.now()}`);
    }, 2000);
  }
}

修改后的AppController

const AppController = (() => {
  function init() {
    const serialPort = new SerialPortController();
    
    // 订阅串口的'data'事件
    serialPort.on('data', (data) => {
      handleSerialData(data);
    });

    serialPort.sendData('请求设备状态');
  }

  function handleSerialData(data) {
    console.log(`AppController处理数据: ${data}`);
    // 你的业务逻辑写在这里
  }

  return {
    init: init
  };
})();

AppController.init();

为什么这两种方案能解决问题?

原来的SerialPortController只负责自己处理数据,和上层AppController完全脱节。现在通过回调或者事件机制,我们把数据传递的通道打开了:SerialPortController只专注于串口的收发,而数据的业务逻辑交给上层的AppController处理,既符合模块化的单一职责原则,也解决了模块间的通信问题。

内容的提问来源于stack exchange,提问作者Enginebeat

火山引擎 最新活动