首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

使用系统端口的统一设计(一)

2012-09-21 
应用系统端口的统一设计(一)本设计不通用,只针对特定的一类问题。如果系统经常和多种端口打交道,例如:COM,T

应用系统端口的统一设计(一)
本设计不通用,只针对特定的一类问题。
如果系统经常和多种端口打交道,例如:COM,TCP,UDP,短信,打印机等等外接端口通讯,那么可以这样设计。

每种通讯方式都是类似,连接,打开端口,接收和发送数据,解析数据给系统。

所以可以统一起来进行设计,这样扩充端口更加容易。

使用C#语言描述

    public delegate void GameEventDelegate(object sender, Action action);// public class Action : EventArgs    {        public PlayPort Receiver = PlayPort.Logic;        public Action(PlayPort sender, ICommand command)        {            Sender = sender;            Receiver = PlayPort.Logic;            Command = command;        }        public Action(PlayPort sender, PlayPort receiver, ICommand command)        {            Sender = sender;            Receiver = receiver;            Command = command;        }        public PlayPort Sender { get; set; }        public ICommand Command { get; set; }    }//端口服务接口    public interface IPortService    {        event GameEventDelegate OnPort;        void Write(Action action);    }


Write函数:向设备写入数据
OnPort事件接收数据,并通知系统接收数据
Java代码和上面类似!

扩展接口可以这样
 public class ControlPanelPort : IPortService    {        private static ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);        private ConfigManager config;        private ControlPanelExecutor executor = new ControlPanelExecutor();        ControlPanelPortQueueManager controlPanelPortQueueManager = new ControlPanelPortQueueManager();        private IPersistService persistService;        public event EventHandler DataArrived;        public IDataParser Parser        {            set            {                controlPanelPortQueueManager.Parser = value;                controlPanelPortQueueManager.Start();            }        }        public Queue<byte[]> DataQueue = new Queue<byte[]>();        public ControlPanelPort(IPersistService persistService)        {            this.persistService = persistService;            config = ConfigManager.Instance(persistService.LoadConfig());            Init();        }        public SerialPort ControlPanelSerialPort { get; set; }        #region IPortService Members        public event GameEventDelegate OnPort;        /// <summary>        /// action中的data格式必须为int[]        /// </summary>        /// <param name="action"></param>        public void Write(Action action)        {            try            {                if (action.Receiver != PlayPort.ControlPanel) return;                if (ControlPanelSerialPort != null && ControlPanelSerialPort.IsOpen)                    executor.Execute(this, action);            }            catch (IOException ex)            {                log.Error(ex.Message,ex);                if(ControlPanelSerialPort!=null)                    ControlPanelSerialPort.Close();            }        }        #endregion        //        private void Init()        {            try            {                ControlPanelSerialPort = new SerialPort("control panel");                ControlPanelSerialPort.PortName = config[ConfigKey.控制面板串口];                ControlPanelSerialPort.BaudRate = 57600;                ControlPanelSerialPort.Handshake = Handshake.None;                ControlPanelSerialPort.DataBits = 8;                ControlPanelSerialPort.StopBits = StopBits.One;                ControlPanelSerialPort.Parity = Parity.None;                ControlPanelSerialPort.ReceivedBytesThreshold = 2;                ControlPanelSerialPort.WriteTimeout = SerialPort.InfiniteTimeout;                ControlPanelSerialPort.ReadTimeout = SerialPort.InfiniteTimeout;                ControlPanelSerialPort.DataReceived += controlPanelPort_DataReceived;                ControlPanelSerialPort.Open();                ControlPanelSerialPort.DiscardInBuffer();                ControlPanelSerialPort.DiscardOutBuffer();                //                controlPanelPortQueueManager.ControlPort = this;            }            catch (Exception ex)            {                log.Error("控制面板端口初始化失败!" + ex.Message);            }        }                private void controlPanelPort_DataReceived(object sender, SerialDataReceivedEventArgs e)        {            try            {                                if (OnPort != null)                {                    if (ControlPanelSerialPort == null) return;                    Application.DoEvents();                    Thread.Sleep(50);                    byte[] data = new byte[ControlPanelSerialPort.BytesToRead];                    ControlPanelSerialPort.Read(data, 0, data.Length);                    log.Warn("<<<<接收控制面板信息,length:" + data.Length);                    DataQueue.Enqueue(data);                    if (DataArrived != null)                    {                        DataArrived(this, null);                    }                }            }            catch (Exception ex)            {                log.Error(ex.Message, ex);            }        }        public void FireOnPort(Action action)        {            if(OnPort!=null)            {                OnPort(this, action);            }        }    }

其他所有的端口扩展都是类似的
在接受端口数据后,将数据直接放到处理队列里面,不要直接将处理代码放到这里,否则影响端口的继续工作,接收数据。不可以认为数据一次性都直接收完毕,数据可能是多次才能接受完成,所以处理的时候都要将数据放到队列里面,然后通过另一个线程处理。

数据接收函数
controlPanelPort_DataReceived
将数据放到队列中
DataQueue.Enqueue(data);
处理完毕后,触发事件,通知订阅者
OnPort(this, action);

Write数据到端口的执行者:ControlPanelExecutor
处理队列数据的管理者:ControlPanelPortQueueManager
持久化服务:IPersistService

其他端口都是类似处理!!!
下面将所有端口统一起来
public class PortProxy : IPortService
PortProxy类型是向前端表露的统一端口代理
他统一了所有端口的访问方式,这里使用了Proxy模式
 public class PortProxy : IPortService    {        private static ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);        private IPortService communicationPortService1;        private IPortService monitorPortService;        private IPortService controlPanelPortService1;        private IPortService printPortService1;        private IPortService tcpPortService1;        private IPortService sMSPortService;                public IPortService CommunicationPortService        {            set            {                communicationPortService1 = value;                communicationPortService1.OnPort += Event_OnPort;            }        }        public IPortService MonitorPortService        {            set            {                monitorPortService = value;                monitorPortService.OnPort += Event_OnPort;            }        }        public IPortService PrintPortService        {            set            {                printPortService1 = value;                printPortService1.OnPort += Event_OnPort;            }        }        public IPortService ControlPanelPortService        {            set            {                controlPanelPortService1 = value;                controlPanelPortService1.OnPort += Event_OnPort;            }        }        public IPortService TcpPortService        {            set            {                tcpPortService1 = value;                tcpPortService1.OnPort += Event_OnPort;            }        }        public IPortService SMSPortService        {            set            {                sMSPortService = value;                sMSPortService.OnPort += Event_OnPort;            }        }                #region IPortService Members        public event GameEventDelegate OnPort;        public void Write(Action action)        {            switch (action.Receiver)            {                case PlayPort.ControlPanel:                    {                        controlPanelPortService1.Write(action);                    }                    break;                case PlayPort.Printer:                    {                        printPortService1.Write(action);                    }                    break;                case PlayPort.Udp:                    {                        communicationPortService1.Write(action);                    }                    break;                case PlayPort.Tcp:                    {                        tcpPortService1.Write(action);                    }                    break;                case PlayPort.SMS:                    {                        sMSPortService.Write(action);                    }                    break;                case PlayPort.Monitor:                    {                        monitorPortService.Write(action);                    }                    break;                default:                    Event_OnPort(this, action);                    break;            }        }        #endregion        private void Event_OnPort(object sender, Action action)        {            if (OnPort != null)                OnPort(sender, action);        }    }


他代理了所有的端口,另外值得说明的是他充当了一个逻辑接口,该接口是一个虚拟的系统之间通信的接口,并不代表一个实际存在的接口,该接口的存在大大减少了系统模块之间的耦合性
应用的时候通过注入将可以将Port实例注入了
 public abstract class AbstractGameState : IGameState    {        protected IPortService logic;        //        protected const PlayPort LOGIC_PORT = PlayPort.Logic;        protected const PlayPort CONTROL_PANEL_PORT = PlayPort.ControlPanel;        protected const PlayPort PRINTER_PORT = PlayPort.Printer;        protected const PlayPort SMS_PORT = PlayPort.SMS;        protected const PlayPort UDP_PORT = PlayPort.Udp;        #region IGameState Members        public IPortService PortService        {            set            {                logic = value;                logic.OnPort += Logic_OnPortEvent;            }            get            {                return logic;            }        }        protected abstract void Logic_OnPortEvent(object sender, Action action);    }

这里面的logic即使端口,他代表了所有的端口服务,通过它可以访问所有的端口,端口服务的客户访问大大简化,也与所有的具体端口松耦合,维护上大为简化

访问方法:
 SingleCommand command = SingleCommand.Instance[CommandCode.指令]; command.Data = printParams; logic.Write(new Action(PlayPort.Logic, PlayPort.Printer, command));

表示逻辑端口想打印机发送指令,进行打印
数据接收会触发OnPort事件
客户可以通过该事件进行程序处理
 public abstract class AbstractSingleGameState:AbstractGameState    {        protected override void Logic_OnPortEvent(object sender, Action action)        {            //            if(GameContext.GameState==null) return;            if (GameContext.GameState.CurrentState == CurrentState)            {                try                {                    ActionChainNode stateListener = ActionLockStateManager.Instance;                    if (stateListener.Process(this, action)) return;                    ThreadPool.QueueUserWorkItem(new WaitCallback(Doo),action);                                        OnPortEvent(sender, action);                                   }                catch (Exception ex)                {                    log.Error(ex.Message,ex);                }            }        }              private static ActionChainNode globalChain = GlobalActionChainFactory.GetChain();        protected void Doo(object state)        {            //将不是立即执行的命令填出gamestate栈中,等到actionFilterChain的调用            ActionChainNode stackChain = GlobalActionStackFactory.GetChain();            stackChain.Process(this, (Action) state);            //            globalChain.Process(this, (Action)state);        }        protected virtual void OnPortEvent(object sender, Action action)        {        }    }

程序通过Logic_OnPortEvent处理程序进行接受指令的处理
这里使用了职责链模式进行所有的指令处理,下一节将写出该模式的设计

该处理函数既可以处理全局指令,也可以处理当前状态指令,并将事件进行传递。
传递到具体的处理类
    public class StepWaitingState : AbstractSingleGameState    {        public override GameState CurrentState        {            get { return GameState.StepWaiting; }        }        public StepWaitingState()        {        }                public override object Enter(Action action)        {        }        protected override void OnPortEvent(object sender, Action action)        {            Doo(action);        }        private void Doo(object state)        {            Action action = (Action) state;            ActionChainNode controlPanelActionChain = WatingActionChainFactory.GetChain();            controlPanelActionChain.Process(this, action);        }        public override IGameState Transit(Action action)        {            if (GameContext.GameState.CurrentState == CurrentState)                GameContext.SetState(StateFactory.StepPost, action);            return GameContext.GameState;        }    }


如果接受的指令数据传递到当前状态后,通过该状态的职责链进行处理
ActionChainNode controlPanelActionChain = WatingActionChainFactory.GetChain();

整体就是这样了!

端口代理的实例化
<object id="PortProxy" type="Single.Core.PortProxy,Single.Core"><property name="CommunicationPortService" ref="UdpPort"/><property name="PrintPortService" ref="PrintPort"/><property name="ControlPanelPortService" ref="ControlPanelPort"/><property name="TcpPortService" ref="TcpPort"/><property name="SMSPortService" ref="SMSPort"/><property name="MonitorPortService" ref="UdpMonitorPort"/></object>


PortProxy的注入
<object id="AbstractStateBase" abstract="true"><property name="PortService" ref="PortProxy"/><property name="PersistService" ref="SinglePersistService"/></object>


综上,这样设计之后,客户在使用的过程中所有的细节都没有接触,只是统一通过PortProxy进行通信,所有的端口扩展也都通过ProtProxy进行扩充,不影响客户使用,扩展也更容易,端口的扩展继承统一的PortService,扩展方式统一!

原始链接
http://qixin000.iteye.com/blog/1425135

热点排行