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




