核销校验矩阵通过枚举统一管理校验类型,每个枚举值内嵌静态校验器类实现couponprecheck接口,职责内聚且符合开闭原则;校验全部执行并聚合失败消息,支持数据库配置动态启用校验项,新增校验只需扩展枚举及内部类。

理解核销校验矩阵的核心需求
优惠券核销前需要同时检查多个维度:用户资格、券状态、时间有效性、订单金额匹配等。把这些校验逻辑硬编码在Service里会导致分支爆炸、难以维护、新增规则需改主流程。用枚举统一管理校验类型,再为每种校验定义专属的静态内部类,能天然实现“一个枚举值对应一套完整校验能力”,做到职责内聚、开闭原则落地。
定义主枚举并内嵌校验器类
每个枚举常量代表一类校验场景(如USER_ELIGIBILITY、COUPON_STATUS),其静态内部类实现CouponPreCheck接口,封装具体判断逻辑和失败提示:
示例结构:
public enum CouponCheckType {
USER_ELIGIBILITY {
@Override
public CouponPreCheck getChecker() {
return new UserEligibilityChecker();
}
},
COUPON_STATUS {
@Override
public CouponPreCheck getChecker() {
return new CouponStatusChecker();
}
};
public abstract CouponPreCheck getChecker();
// 内嵌校验器实现类
private static class UserEligibilityChecker implements CouponPreCheck {
@Override
public CheckResult check(CouponContext ctx) {
if (!ctx.getUser().isVip()) {
return CheckResult.fail("仅VIP用户可使用该券");
}
return CheckResult.success();
}
}
private static class CouponStatusChecker implements CouponPreCheck {
@Override
public CheckResult check(CouponContext ctx) {
if (ctx.getCoupon().getStatus() != CouponStatus.ACTIVE) {
return CheckResult.fail("优惠券不可用");
}
return CheckResult.success();
}
}
}
组合执行与失败聚合
校验不追求短路,而是全部执行后汇总所有失败项——这对用户友好(一次性看到全部问题)也利于运营排查:
- 遍历CouponCheckType.values(),调用每个getChecker().check(ctx)
- 收集所有CheckResult.isFailed()的结果到List
- 任一失败即返回整体不通过,附带全部错误消息
扩展性与配置化衔接
实际项目中,不同券种启用的校验项不同。可在数据库为券模板配置check_types字段(如"USER_ELIGIBILITY,COUPON_STATUS,ORDER_AMOUNT"),运行时按字符串匹配枚举值,动态构建校验链:
关键代码片段:
List<couponchecktype> enabledChecks = Arrays.stream(checkTypeStr.split(","))
.map(String::trim)
.map(CouponCheckType::valueOf)
.collect(Collectors.toList());
for (CouponCheckType type : enabledChecks) {
CheckResult result = type.getChecker().check(context);
if (!result.isSuccess()) failures.add(result.getMessage());
}
</couponchecktype>
这样新增一种校验(如SHOP_BLACKLIST),只需增加枚举常量+静态内部类,无需改动任何调用方或配置解析逻辑。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











