zoukankan      html  css  js  c++  java
  • 使用责任链模式消除if分支实践

    之前接手过一个车辆监控的工具,接受第三方推送过来的车辆状态数据然后入库。车辆状态一共有8种之多,每种状态都需要做不同 处理操作。刚接手这份代码时,针对此处处理,是庞大的if-else结构,if-else分支一多,分支内部逻辑再一复杂,到时候有多坑爹,我想接触过的人一定知道。说代码是艺术,这话对,但现在不想谈艺术,只是这代码看着fuck,怎能不优化。之前学习过设计模式,看到代码时立刻就想到了责任链模式,于是开干。至于具体责任链模式比较简单,各位道行也比较深,不多说。

    1、定义抽象基处理器:

    public abstract class BaseHandler
        {
            #region Private Fields
    
            private readonly VehicleStatus _vehicleStatus;
    
            private readonly BaseHandler _nextHandler;
    
            #endregion
    
            #region Protected Fields
    
            protected readonly CarStatusMsgTextBLL _statusMsgTextBLL = new CarStatusMsgTextBLL();
    
            protected readonly CarStatusBLL _statusBLL = new CarStatusBLL();
    
            #endregion
    
            #region Constructors
    
            public BaseHandler(VehicleStatus vehicleStatus, BaseHandler nextHandler)
            {
                _vehicleStatus = vehicleStatus;
                _nextHandler = nextHandler;
            }
    
            #endregion
    
            #region Protected Methods
    
            protected virtual void ExecuteHandle(CarMessage carMessage)
            {
                //不再记录CarStatusMsgText,数据量太大
                //CarStatusMsgText msgText = new CarStatusMsgText
                //{
                //    Sys_Guid = Guid.NewGuid().ToString("N").ToUpper(),
                //    CreateDate = DateTime.Now,
                //    MsgText = carMessage.MessageContent
                //};
                //_statusMsgTextBLL.AddCarStatusMsgText(msgText);
            }
    
            #endregion
    
            #region Public Methods
    
            public void Handle(CarMessage carMessage)
            {
                if (carMessage.VehicleStatus == _vehicleStatus)
                {
                    this.ExecuteHandle(carMessage);
                }
                else if (_nextHandler != null)
                {
                    _nextHandler.Handle(carMessage);
                }
                else
                {
                    throw new Exception("未识别的消息类型:" + carMessage.MessageContent);
                }
            }
    
            #endregion
        }

    其中protected virtual void ExecuteHandle(CarMessage carMessage)这二个虚方法实现各具体处理器中公共的处理逻辑。具体来说,针对第三方推送过来的原始报文,我们需要保留一份,这个是针对所有状态的,所以就放在这里。

    public void Handle(CarMessage carMessage)的作用类似模板方法模式中的那个模板方法,具体逻辑就是,如果当前消息类别(或者叫车辆状态)等于自己应该处理的类别,则自己处理,如果不能处理或不应该处理,则调用链中下一个处理器。


    2、各具体状态对应的处理器
    实际业务中, 第三方推送过来的状态有8种,分别代表停车、熄火、进入目的地1公里以内、离开目的地1公里以外、超速、暴力行驶等等,如下截图:

    这里以停车和进入1公里以内来示例责任链中的责任方实现

    public class StoppedHandler : BaseHandler
        {
            #region Constructors
    
            public StoppedHandler(BaseHandler nextHandler)
                : base(VehicleStatus.Stopped, nextHandler)
            {
    
            }
    
            #endregion
    
            #region Protected Methods
    
            protected override void ExecuteHandle(CarMessage carMessage)
            {
                base.ExecuteHandle(carMessage);
    
                CarStatus carStatus = JsonConvert.DeserializeObject<CarStatus>(carMessage.MessageContent);
                carStatus.Sys_Guid = Guid.NewGuid().ToString("N").ToUpper();
                carStatus.CreateDate = DateTime.Now;
    
                _statusBLL.AddCarStatus(carStatus);
            }
    
            #endregion
        }
    public class EnterNearbyHandler : BaseHandler
        {
            #region Constructors
    
            public EnterNearbyHandler(BaseHandler nextHandler)
                : base(VehicleStatus.EnterNearby, nextHandler)
            {
    
            }
    
            #endregion
    
            #region Protected Methods
    
            protected override void ExecuteHandle(CarMessage carMessage)
            {
                base.ExecuteHandle(carMessage);
    
                CarStatus carStatus = JsonConvert.DeserializeObject<CarStatus>(carMessage.MessageContent);
                carStatus.Sys_Guid = Guid.NewGuid().ToString("N").ToUpper();
                carStatus.CreateDate = DateTime.Now;
                carStatus.ReqIds = carStatus.RequestId;
                _statusBLL.AddCarStatus(carStatus);
    
                if (!string.IsNullOrWhiteSpace(carStatus.ReqIds)
                    && carStatus.ReceiveTime.HasValue)
                {
                    _statusBLL.UpdateSignInTime(carStatus.ReqIds, carStatus.MobileNumber, carStatus.ReceiveTime.Value);
                    _statusBLL.ExecuteQuQian(carStatus.ReqIds);
                }
            }
    
            #endregion
        }

    看到没,各责任方各自的逻辑都不同,而且各自只需要关心自己的责任(需要处理的业务逻辑)。

    3、责任链的构造及调用

    private readonly BaseHandler _carMessageHandler = new StoppedHandler(
                        new StalledHandler(
                            new ACCOnAndFullSpeedHandler(
                                new ViolentDrivingHandler(
                                    new EnterNearbyHandler(
                                        new ParkingTimeoutHandler(
                                            new ParkingTimeoutImgHandler(
                                                new LeaveNearbyHandler(null))))))));
    CarMessage carMessage = new CarMessage
                {
                    VehicleStatus = (VehicleStatus)Convert.ToInt32(jsonObj["msgType"]),
                    MessageContent = message.Text
                };
    
                _carMessageHandler.Handle(carMessage);

    4、注意点

    1)并不是具体业务对应多少状态,我们就需要有多少个处理器(责任方),例如本例中,虽然第三方推送过来8种状态,但假设停车和熄火都只需要记录消息报文,进入1公里才需要有特定的业务逻辑,那么停车和熄火这两种状态可以只定义一个处理器

    2)关于责任链的构建,鉴于责任链上处理器的数目可能会比较多,如果每次收到消息都重新构建责任链再处理消息,太耗性能了,推荐构建一个责任链,处理所有消息

     
  • 相关阅读:
    Python驱动SAP GUI完成自动化(三)
    Python驱动SAP GUI完成自动化(选择布局+动态获取节点值)
    python中如何将货币数字转化成汉字大写金额
    python requests无法上传中文文件名的文件
    requests库结合selenium库共同完成web自动化和爬虫工作
    利用python第三方库提取PDF文件的表格内容
    pyinstaller打包exe文件闪退的解决办法
    pandas数据分析小知识点(一)
    java 终端输入小结,输入到数组、文件等(持续更新)
    Maven jenkins +Jmeter自动化测试
  • 原文地址:https://www.cnblogs.com/guokun/p/6404853.html
Copyright © 2011-2022 走看看