尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
工厂模式在设备驱动中的应用
C# 上位机开发 - 工厂模式在设备驱动中的应用一篇搞定 建议收藏作者萨达大 | 标签工厂模式、设备驱动、上位机、配置化导读现场常见「同一套软件A 线 Modbus RTUB 线 Modbus TCPC 线厂家私有协议」。用工厂 配置创建IDeviceDriverUI 与业务层只依赖接口换设备不改代码。一、问题场景if-else 地狱不少项目启动类里写着if(settings.UseTcp)drivernewModbusTcpDriver(...);elseif(settings.UseRtu)drivernewModbusRtuDriver(...);elsedrivernewCustomProtocolDriver(...);窗体、服务、测试里复制粘贴三遍新增一种驱动就要改 N 处。工厂模式把「创建哪种驱动」收敛到一个工厂类 一份配置。二、统一抽象IDeviceDriver与分层架构 01 篇一致驱动层只关心连接与收发详见上一篇 HAL。此处扩展为多种实现实现类适用场景连接参数ModbusRtuDriverRS485/RS232端口名、波特率、校验ModbusTcpDriver以太网 PLCIP、端口通常 502CustomProtocolDriver扫码枪、称重仪等串口或 TCP 自定义结束符publicinterfaceIDeviceDriver:IAsyncDisposable{stringName{get;}boolIsConnected{get;}TaskConnectAsync(CancellationTokenctdefault);TaskDisconnectAsync(CancellationTokenctdefault);Taskbyte[]TransceiveAsync(byte[]request,inttimeoutMs,CancellationTokenctdefault);}三、ModbusRtuDriver 示例publicsealedclassModbusRtuDriver:IDeviceDriver{privatereadonlySerialPort_port;publicstringNameModbusRtu;publicboolIsConnected_port.IsOpen;publicModbusRtuDriver(stringportName,intbaudRate,Parityparity){_portnewSerialPort(portName,baudRate,parity,8,StopBits.One);}publicTaskConnectAsync(CancellationTokenctdefault){if(!_port.IsOpen)_port.Open();returnTask.CompletedTask;}publicTaskDisconnectAsync(CancellationTokenctdefault){if(_port.IsOpen)_port.Close();returnTask.CompletedTask;}publicasyncTaskbyte[]TransceiveAsync(byte[]request,inttimeoutMs,CancellationTokenctdefault){_port.Write(request,0,request.Length);varbufnewbyte[512];varreadawaitTask.Run(()_port.Read(buf,0,buf.Length),ct);returnbuf.AsSpan(0,read).ToArray();}publicasyncValueTaskDisposeAsync(){awaitDisconnectAsync();_port.Dispose();}}四、ModbusTcpDriver 示例publicsealedclassModbusTcpDriver:IDeviceDriver{privatereadonlystring_host;privatereadonlyint_port;privateTcpClient?_client;publicstringNameModbusTcp;publicboolIsConnected_client?.Connectedtrue;publicModbusTcpDriver(stringhost,intport502){_hosthost;_portport;}publicasyncTaskConnectAsync(CancellationTokenctdefault){_clientnewTcpClient();await_client.ConnectAsync(_host,_port,ct);}publicTaskDisconnectAsync(CancellationTokenctdefault){_client?.Close();returnTask.CompletedTask;}publicasyncTaskbyte[]TransceiveAsync(byte[]request,inttimeoutMs,CancellationTokenctdefault){if(_clientnull)thrownewInvalidOperationException(Not connected);varstream_client.GetStream();awaitstream.WriteAsync(request,ct);varbufnewbyte[512];varnawaitstream.ReadAsync(buf,ct);returnbuf.AsSpan(0,n).ToArray();}publicasyncValueTaskDisposeAsync(){awaitDisconnectAsync();_client?.Dispose();}}五、CustomProtocolDriver自定义 ASCII 协议例如设备返回ST,GS,0012.34kg\r\npublicsealedclassCustomProtocolDriver:IDeviceDriver{privatereadonlySerialPort_port;publicstringNameCustomAscii;publicboolIsConnected_port.IsOpen;publicCustomProtocolDriver(stringportName,intbaudRate){_portnewSerialPort(portName,baudRate);_port.NewLine\r\n;}publicTaskConnectAsync(CancellationTokenctdefault){if(!_port.IsOpen)_port.Open();returnTask.CompletedTask;}publicTaskDisconnectAsync(CancellationTokenctdefault){if(_port.IsOpen)_port.Close();returnTask.CompletedTask;}publicTaskbyte[]TransceiveAsync(byte[]request,inttimeoutMs,CancellationTokenctdefault){_port.Write(request,0,request.Length);varline_port.ReadLine();returnTask.FromResult(Encoding.ASCII.GetBytes(line));}publicasyncValueTaskDisposeAsync(){awaitDisconnectAsync();_port.Dispose();}}协议解析仍在协议层Driver 只保证「发命令、收一行」。六、DeviceDriverFactory配置驱动创建6.1 配置模型publicsealedclassDriverConfig{publicstringDriverType{get;set;}ModbusRtu;// ModbusRtu | ModbusTcp | CustomAsciipublicstring?PortName{get;set;}publicintBaudRate{get;set;}9600;publicstringParity{get;set;}Even;publicstring?Host{get;set;}publicintTcpPort{get;set;}502;}6.2 JSON 配置示例devices.json{LineA:{DriverType:ModbusRtu,PortName:COM3,BaudRate:9600,Parity:Even},LineB:{DriverType:ModbusTcp,Host:192.168.1.10,TcpPort:502},Scale1:{DriverType:CustomAscii,PortName:COM5,BaudRate:2400}}6.3 工厂实现publicstaticclassDeviceDriverFactory{publicstaticIDeviceDriverCreate(DriverConfigcfg){switch(cfg.DriverType){caseModbusRtu:varparityEnum.ParseParity(cfg.Parity);returnnewModbusRtuDriver(cfg.PortName!,cfg.BaudRate,parity);caseModbusTcp:returnnewModbusTcpDriver(cfg.Host!,cfg.TcpPort);caseCustomAscii:returnnewCustomProtocolDriver(cfg.PortName!,cfg.BaudRate);default:thrownewNotSupportedException($Unknown driver:{cfg.DriverType});}}publicstaticDictionarystring,IDeviceDriverCreateAll(IConfigurationconfiguration){varsectionconfiguration.GetSection(Devices);vardictnewDictionarystring,IDeviceDriver();foreach(varchildinsection.GetChildren()){varcfgchild.GetDriverConfig()??newDriverConfig();dict[child.Key]Create(cfg);}returndict;}}启动时vardriversDeviceDriverFactory.CreateAll(builder.Configuration);varlineAProtocolnewModbusProtocolClient(drivers[LineA]);varservicenewDeviceService(lineAProtocol);换 B 线设备只改devices.json里LineB的DriverType与参数零 UI 改动。七、与分层架构的配合devices.jsonDeviceDriverFactoryIDeviceDriverModbusProtocolClientDeviceServiceMainForm工厂只出现在应用启动 / DI 注册阶段业务代码不出现new ModbusRtuDriver。八、依赖注入可选进阶ASP.NET Core 风格注册services.AddSingletonIDeviceDriver(sp{varcfgsp.GetRequiredServiceIConfiguration().GetSection(Devices:LineA).GetDriverConfig()!;returnDeviceDriverFactory.Create(cfg);});services.AddSingletonIProtocolClient(spnewModbusProtocolClient(sp.GetRequiredServiceIDeviceDriver()));services.AddSingletonDeviceService();WinForms 可在Program.cs里手动组装原理相同。九、切换设备实战 checklist步骤操作1确认新设备物理连接COM/IP2修改 JSON 中DriverType与参数3若协议不同换IProtocolClient实现仍通过工厂或第二个工厂4业务寄存器地址在配置表维护不改 Form5用 Mock Driver 跑一遍回归测试十、常见问题 FAQQ1工厂和抽象工厂有什么区别本文是简单工厂按字符串创建上位机足够用。若驱动种类爆炸且族系复杂可升级为抽象工厂 产品族但维护成本更高。Q2多个设备共用一个串口网关怎么办一个ModbusRtuDriver实例多个ModbusProtocolClient共用同一 Driver 时需加互斥锁或网关 SDK 在 HAL 内排队。Q3配置放 JSON 还是数据库单机工控机 JSON 热更新已够用多产线 MES 下发可用数据库工厂读表生成DriverConfig。Q4DriverType 用字符串还是枚举配置文件用字符串可读性好工厂内switch或字典注册FuncDriverConfig, IDeviceDriver避免巨型 switch。Q5如何单元测试工厂注入临时 JSONCreate后断言Name、IsConnected为 false用 Mock 串口需接口隔离或ISerialPortWrapper。Q6和 01 篇 HalSerialPort 重复吗HalSerialPort是教学用 HALModbusRtuDriver是现场命名。可合并为一个类只要实现IDeviceDriver即可。十一、小结所有硬件差异收敛到IDeviceDriver实现类。DeviceDriverFactory JSON实现换线不换代码。UI 只依赖DeviceService不依赖具体 Driver。下一篇介绍轮询数据如何推送到界面——观察者模式与绑定。上一篇01 上位机分层架构设计下一篇03 观察者模式与数据绑定
RELATED

相关推荐

基于DHDMS层级全息折叠压缩的P=NP形式化证明与通用自举编译器工程实现

基于DHDMS层级全息折叠压缩的P=NP形式化证明与通用自举编译器工程实现

NP难问题的多项式时间解法:基于DHDMS层级全息折叠压缩的PNP形式化证明与通用自举编译器工程实现 Polynomial-Time Solution to NP-Hard Problems: Formal Proof of PNP Based on DHDMS Hierarchical Holographic Folding Compression and Engineering Implementatio…

📅 2026/9/16 18:29:41
上位机分层架构设计

上位机分层架构设计

C# 上位机开发 - 上位机分层架构设计(HAL协议层业务层 一篇搞定 建议收藏) 作者:萨达大 | 标签:C#、上位机、分层架构、HAL、Modbus 导读:很多新手把 SerialPort 写在按钮事件里,换一台 PLC 就要改几十个窗…

📅 2026/8/26 10:13:50
为什么你越努力优化,供应链反而越脆弱?

为什么你越努力优化,供应链反而越脆弱?

开篇:一次让我崩溃的多部门会议 去年做年度预算规划,我同时面对三个部门的“合理诉求”: 销售总监说:“客户要的交付率必须做到98%以上,哪怕多备库存。丢一个客户,再找回来比登天还难。” 财务总监说&#…

📅 2026/8/27 4:01:34
MORE NEWS

更多资讯

📰

Java+SSM实现电子商务平台:从数据库设计到部署上线全解析

说实话,我见过太多同学第一次打开“电子商务平台”这个毕设题目时的表情——天天都在用淘宝京东不假,可真到自己动手,要把登录注册、商品展示、购物车、下单、后台管理这一整条链路从零搭起来,很多人一下就不知道从哪下手了。这篇…

📰

Java枚举类全解析:底层机制、高级玩法与面试高频考点

做 Java 开发这些年,我发现一个很有意思的现象:很多写了三五年代码的程序员,对枚举类的认知还停留在“用来定义一组常量”。甚至连“Java基础”里最基础的 enum 用法都能在面试时被问出花样来——问你怎么保证枚举不被反射破坏、问你在 switc…

📰

Altium Designer板框圆弧设计:三种高效方法及实战技巧

1. 板框圆弧不是"画个弧"那么简单 刚入行那会儿,我总觉得PCB板框就是个边界线,画直画弯无所谓,反正板厂能切出来就行。直到有一次做一款手持设备,结构工程师给我发来一个带R角的DXF文件,我随手用直线加圆弧拼…

📰

Google Cloud Skills开发实战:从契约定义到GKE生产部署

1. 项目概述:当“skills”不再只是简历上的单词,而成为可执行、可编排、可演化的智能体能力单元 最近两周,我在三个不同客户的现场部署中,反复被问到同一个问题:“你们说的这个 agent platform,到底怎么定义…

📰

基于LangChain与FAISS的增强版RAG知识库:MMR与HyDE检索优化实战

1. 从"能搜到"到"搜得准":增强版知识库到底在解决什么做过RAG知识库的人大概都有过这种体验:基础版跑通那一刻特别兴奋,文档切好、向量入库、问一句答一句,感觉大功告成。可一旦把真实业务文档丢进去&#xf…

📰

Notepad++ 7.9.5 稳定版配置与 Python Script 批量处理实战

简介:Notepad 7.9.5 是一款面向 Windows 平台的开源文本与源代码编辑器,适合程序员、开发者以及需要频繁处理文本的办公人群使用。它通过语法高亮与语法折叠提升代码编写效率,并支持插件扩展,兼顾轻量、快速与可定制性。本资源为 …

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬