第十节:基于责任链模式做限购商品的前置判断实操
一. 前言
1. 什么是责任链模式?
构建一条处理链,使多个对象可以处理同一个请求,直到该请求被处理为止
2. 场景
(1) 审批场景:不同天数的假期需要不同级别的领导审批。(如多级审批流程:组长→部门经理→总经理)
(2) Asp.Net Core中间件管道:HTTP 请求需要经过多步处理(如认证、授权、缓存、路由等),每个中间件独立处理并决定是否传递给下一个
(3) 日志场景:不同级别 / 类型的日志需要不同的处理器(如输出到控制台、文件、数据库),按优先级处理
3. 好处
责任链模式通过解耦各校验步骤,使系统更适应变化,同时避免了在控制器中写冗长的if-else校验逻辑
4. 本次实操内容
基于责任链模式实现限购商品下单的多级校验,依次完成 参数合法性→用户权限→商品数量(限购 + 库存)→订单金额 校验, 任何一步失败则终止流程。
二. 实操
1. 构建抽象类 LimitOrderHandler
在该类中通过SetNext方法设置下一个处理者,然后声明抽象类Validate,用来处理请求
/// <summary>
/// 定义校验抽象校验类
/// </summary>
public abstract class LimitOrderHandler
{
protected LimitOrderHandler nextHandler; //下一个处理者
/// <summary>
/// 设置下一个处理者
/// </summary>
/// <param name="next"></param>
public void SetNext(LimitOrderHandler next) => nextHandler = next;
//处理请求(返回校验结果:是否通过+错误信息)
public abstract Task<(bool isValid, string errorMsg)> Validate(OrderParam param);
}
2. 构建多个具体的处理者
比如 ParamValidationHandler,实现抽象类LimitOrderHandler
显式实现方法Validate,在里面处理具体业务,同时判断如果有一个处理者,则转向下个处理者
/// <summary>
/// 1. 参数合法性校验处理者
/// </summary>
public class ParamValidationHandler : LimitOrderHandler
{
public override async Task<(bool isValid, string errorMsg)> Validate(OrderParam param)
{
if (param == null) { return (false, "参数为空"); }
if (param.quantity <= 0) { return (false, "购买数量必须大约0"); }
if (param.price <= 0) { return (false, "商品单价必须大约0"); }
if (string.IsNullOrEmpty(param.goodsId)) { return (false, "商品id不能为空"); }
//校验流程走完,如果有下一个处理者,则传递给下一个
if (nextHandler != null)
{
return await nextHandler.Validate(param);
}
return (true, string.Empty);
}
}
/// <summary>
/// 2. 用户权限校验
/// </summary>
public class UserPermissionHandle : LimitOrderHandler
{
public override async Task<(bool isValid, string errorMsg)> Validate(OrderParam param)
{
//校验是否登录--模拟
if (string.IsNullOrEmpty(param.userId)) { return (false, "用户没有登录"); }
//校验是否是会员(限购商品仅仅会员可以购买)--模拟
bool isVip = param.userId != null; //正常应该DB校验
if (!isVip) { return (false, "非VIP用户"); }
//校验流程走完,如果有下一个处理者,则传递给下一个
if (nextHandler != null)
{
return await nextHandler.Validate(param);
}
return (true, string.Empty);
}
}
/// <summary>
/// 3. 商品数量校验
/// </summary>
public class QuantityLimitHandle : LimitOrderHandler
{
public override async Task<(bool isValid, string errorMsg)> Validate(OrderParam param)
{
//1. 限购规则,每人最多买5件
if (param.quantity > 5)
{
return (false, "限购最多买5件");
}
//2. 校验库存是否充足
int stock = 100; //DB查询
if (param.quantity>stock)
{
return (false, "库存不足");
}
//校验流程走完,如果有下一个处理者,则传递给下一个
if (nextHandler != null)
{
return await nextHandler.Validate(param);
}
return (true, string.Empty);
}
}
/// <summary>
/// 4. 订单金额校验
/// </summary>
public class AmountLimitHandler : LimitOrderHandler
{
private const decimal MinAmount = 10; // 最低下单金额
private const decimal MaxAmount = 5000; // 单笔最大金额(限购商品上限
public override async Task<(bool isValid, string errorMsg)> Validate(OrderParam param)
{
var totalAmount = param.quantity * param.price;
if (totalAmount < MinAmount)
return (false, $"订单金额不能低于{MinAmount}元");
if (totalAmount > MaxAmount)
return (false, $"限购商品单笔金额不能超过{MaxAmount}元");
//校验流程走完,如果有下一个处理者,则传递给下一个
if (nextHandler != null)
{
return await nextHandler.Validate(param);
}
return (true, string.Empty);
}
}
3. 初始化多个处理者
在控制器的构造函数中实例化多个处理者,并通过setNext方法设置前后顺序
public class Demo10Controller : Controller
{
private readonly LimitOrderHandler validationChain;
/// <summary>
/// 构造函数中构建责任链
/// </summary>
public Demo10Controller()
{
//1. 创建处理者实例
var paramValidationHandler = new ParamValidationHandler();
var userPermissionHandle = new UserPermissionHandle();
var quantityLimitHandle = new QuantityLimitHandle();
var amountLimitHandler = new AmountLimitHandler();
//2. 构建责任链
paramValidationHandler.SetNext(userPermissionHandle);
userPermissionHandle.SetNext(quantityLimitHandle);
quantityLimitHandle.SetNext(amountLimitHandler);
//抽象类用子类实现
validationChain = paramValidationHandler;
}
}
4.action中调用
使用第一个handler进行处理校验即可,会自动转向各个链条
public class Demo10Controller : Controller
{
private readonly LimitOrderHandler validationChain;
/// <summary>
/// 下单接口
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> PutOrder(OrderParam param)
{
//执行责任链校验
var (isValid, errorMsg) = await validationChain.Validate(param);
if (!isValid) {
return Json(new { status = "error", msg = errorMsg });
}
return Json(new { status = "ok", msg = "下单成功" });
}
}
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。