问题从哪来
很多采集程序是这样演化的:先是 Modbus,写一段;后来加西门子,再写一段 if/else;再后来加三菱,主循环里堆满协议分支。每加一种协议都要动核心代码,回归测试越来越痛苦。
根因是协议实现和采集调度耦合在了一起。
驱动工厂的核心思想
把“每种协议怎么读写”抽象成统一接口,把“什么时候读、读到的数据怎么处理”留给调度层。新增协议 = 新增一个实现了统一接口的驱动文件,主程序一行不改。
统一驱动接口设计
无论哪种协议,对外都暴露同样的能力:
interface IDriver {
connect(config): 连接
disconnect(): 断开
read(tags): 批量读一批点位
write(tag, value): 写单个点位
isConnected(): 当前连接状态
}
每个点位配置里只声明:用哪个驱动(driverType)、地址是什么、数据类型、采集周期。调度层根据 driverType 从“工厂”里取对应驱动实例,完全不关心底层是 Modbus 还是 OPC UA。
一个配置化点位的例子
| 点名 | 驱动 | 地址 | 类型 | 周期ms |
|---|---|---|---|---|
| 压机温度 | modbus-tcp | 40001 | float | 2000 |
| 主轴转速 | s7 | DB1.DBD0 | float | 1000 |
| 报警字 | mc | D100 | uint16 | 500 |
调度层按周期统一轮询,驱动差异被完全屏蔽在配置背后。
这样做的四个收益
- 新增协议不碰核心:实现接口、注册到工厂即可
- 便于单元测试:可以用模拟驱动替代真实 PLC
- 故障隔离:一个驱动崩溃不影响其他协议
- 十年可迭代:协议再多,主程序复杂度不线性增长
落地提醒
- 接口里一定要有
isConnected和统一的重连钩子,断线重连在驱动内部闭环 - 批量读接口比逐个读重要得多,直接决定采集效率(可参考《Modbus TCP 多地址批量读取》一文)
- 驱动实例建议按连接复用,避免每个点位建一条连接
这套模式是构建可长期演进采集平台的地基,前期多花一两天设计接口,后期省的是几个月的维护成本。