使用责任链模式消除if分支实践
时间:2022-07-24
本文章向大家介绍使用责任链模式消除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)关于责任链的构建,鉴于责任链上处理器的数目可能会比较多,如果每次收到消息都重新构建责任链再处理消息,太耗性能了,推荐构建一个责任链,处理所有消息
- 微信小游戏初体验
- 一行Spark代码的诞生记(深度剖析Spark架构)
- Ray:AI的分布式系统
- Spring Boot 中使用 MongoDB 增删改查
- 来人啊给我炸了那个Java虚拟机No.46
- 机器学习虾扯淡之Logistic回归No.44
- 大数据计数原理1+0=1这你都不会算(一)No.47
- 机器学习虾扯蛋之SVD奇异值分解No.48
- 提高Spark姿势水平 No.73
- 好好玩的螺旋算法No.69
- linux学习第四十篇:访问日志不记录静态文件,访问日志切割,静态元素过期时间
- linux学习第四十一篇:配置防盗链,访问控制Directory,访问控制FilesMatch
- linux学习第四十二篇:限定某个目录禁止解析php, 限制user_agent,PHP相关配置
- 简易但不简单的配置中心No.79
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法