当前位置: 首页 > >

设计模式项目实战--命令模式

发布时间:

开通博客已经很多年了,*惯性的看别人写的技术博客,自己确从来没有写的打算。原因有两种,一是觉得写一篇好的博客确实要花费很多时间,时间=金钱吧,毕竟不是啥大师,能够做到信手拈来。二是觉得才疏学浅,写的博客有问题,怕被人拍砖,毕竟技术人员嘛,不会忽悠,有的就是自己这几年敲代码的经验,被人鄙视后,总会觉得自己一无是处吧。


不过最后还是觉得开始养成写博客的*惯,毕竟项目一个个做了,总想有点念想,将自己这几年项目的中用到的设计模式,软件架构之类的东西,总结一下。本人主要是.NET和java开发,今后也会陆陆续续把积累商业项目的工具包源码传到github上去。供大家参考吧。


?


这次谈一下设计模式中的命令模式。命令模式是一个高内聚的模式,其定义为:Encapsulate a request as an object, thereby letting you parameterizeclients with different requests, queue or log requests, and support undoableoperations.(参考-设计模式之禅)。命令模式的通用类图如下所示:







对于命令模式的理解, 以及该模式的优点以及缺点,.NET大家可以参看《大话设计模式》,java人员参考《设计模式之禅》。这里就不多谈了。这里主要谈一下该模式在自己做过的几个项目中是怎样运用的。


?


1.1 业务场景:


由于项目需要,本人需要开发一个CS架构的服务器端程序,完成的功能是实现前端传感器的数据的采集入库。通讯方式是采用串口通讯,实现ms级数据的刷新。那好问题来了。


第一:虽然都是串口通讯,但是前端传感器种类不一,存在多种传感器。熟悉硬件的都知道,不同类别的传感器串口协议不一样,导致解析肯定不一样。以下是一个典型串口协议字段定义图。


?


同步

(SYNC)

起始

(STX)

数据长度

(LEN)

指令

(CMD)

数据体

(DATA)

校验

(CRC)

1byte

1byte

1byte

1byte

最大 252byte

2byte

?

?

数据长度(LEN)


?


第二:系统还需考虑后续新类型的传感器接入,所以对于系统扩展性要求较高


第三:要实现ms级的数据刷新。


?


1.2整体架构


???????? 服务器端:以windowsservice的形式注册到系统中,实现一个后台对于前端传感器数据采集、解析、入库的功能。


???????? 客户端:采用remoting技术,从服务器端获取传感器信息,在客户端上显示。


? 1.3命令模式的应用实例


?



1.3.1 串口通讯类


既然是要从串口读取数据,当然要有串口通信类了哦。以下是串口通讯类













这个类没什么好说的,主要就是一些串口的操作,值得一提的是事件onReceiveMessage。这个事件的调用是在串口收到数据的时候调用。该部分的初始化工作如下:


? ?stringCMportNumber =ApplicationProperties.CMportNumber;


??? intCMdataBits =ApplicationProperties.CMdataBits;


? ??int CMbaudRate=ApplicationProperties.CMbaudRate;


??? intCMpacketSize =ApplicationProperties.CMpacketSize;


serialPort0 = newCommSerialPort(CMportNumber, CMbaudRate,CMdataBits,CMpacketSize);


??? ITerminalcmSensorTerminal =newCMSensorTerminal();


??? serialPort0.onReceiveMessage += new CommSerialPort.onMessageHandle(cmSensorTerminal.ReviveData);


CMSensorTerminal即是我们的众多传感器中的一种,暂且叫做CM传感器





1.3.2双队列缓存方式实现数据上传入库


?


以上则完成了串口类的初始化工作,并且将传感器CM的监听事件(ReceiveData)注册上去,只要该串口有数据传入,及调用该CMSensorTerminal类得ReceiveData函数,进行解析,可能有人会说既然都接送到了数据,那我们直接在receiveData函数里面直接解析数据,然后Insert到数据库不就行了吗?这样是不行的,现实中我们传感器采集要求是ms级的,直接采用进行ADO的操作是不行的,联想到操作系统的消息队列,那好,我们采用双队列的模式,进行处理。这里我们引入DataHandlerThread类,









这个后台线程类维护了2个队列,一个是receiveCommand队列,另外一个是processCommand队列,这个类的功能即是不断的将receiveCommand队列的命令,推送到processCommand队列中去(注意加锁),这里的命令即是我们不同类传感器数据的插入命令。这个类扮演的即是一个缓存的角色,将大量的传感器入库命令先传入receiveCommand队列,然后在推入processCommand队列。


第二个类是dataprocessThread类








这个类得主要功能,即是将processCommand队列中的命令提取出来,进行入库处理。真实的入库处理是在这个类里面直接处理的吗?不是,而是采用命令模式,这个类扮演的是一个invoker的角色,每类传感器都是在其对应的dataprovider里面进行处理的。例如CMCommand传感器,对应于CMSensorProvider(对应命令模式里面的receiver)








总结:再看最后我们解决了三个业务问题了吗?


1.??????新类型传感器的扩展


只需继承TerminalCommand,编写该传感器的dataprovider类,在该类里面进行DAO操作即可,做到对修改封闭,对扩展开放的原则。无所修改现有代码


2.??????毫秒级刷新


在datahandler类里面,只需创建多个dataprocessThread类,开启多个线程对于同一命令队列进行处理即可。


3.??????不同串口协议的解析


由于命令模式对命令的扩展很方便,所以上述问题完成可以在Command中得到解决


?


Ps:可能有人说串口太简单了吧?搞这么麻烦,大家仔细注意下,主要把串口类改成socket操作类,我们就可以实现了基于socket操作的服务器端了,后续command,receiver,invoker(双队列处理)架构完全可以不变。实际项目中可正是这样做的。


代码太多,就没有贴了,稍后给出github地址,上传的都是实际商业项目中的干货,给大家分享???????????????????????????????????? ?????????????????????????????????????????????????????????????????????????? ---Predator.Zhang?












友情链接: 高中资料网 职业教育网 成人教育网 理学 大学工学资料