使用责任链模式消除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)关于责任链的构建,鉴于责任链上处理器的数目可能会比较多,如果每次收到消息都重新构建责任链再处理消息,太耗性能了,推荐构建一个责任链,处理所有消息
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?