Bootstrap

优惠券平台(一):基于责任链模式创建优惠券模板

前景概要

系统的主要实现是优惠券的相关业务,所以对于用户管理的实现我们简单用拦截器在触发接口前创建一个单一用户。

// 用户属于非核心功能,这里先通过模拟的形式代替。后续如果需要后管展示,会重构该代码
UserInfoDTO userInfoDTO = new UserInfoDTO("1810518709471555585", 
"pdd45305558318", 
1810714735922956666L);
UserContext.setUser(userInfoDTO);

优惠券模板创建业务

优惠券分为平台券和店铺券,平台券由平台运营人员创建和管理员审批,关系隶属于平台,用户使用后成本一般来说由平台和商家共同承担;而店铺券由商家在商家后台直接创建,无需审核,成本由店家独自承担。

设定优惠券的领取规则,消耗规则:

// 领取规则
JSONObject receiveRule = new JSONObject();
receiveRule.put("limitPerPerson", 1); // 每人限领
receiveRule.put("usageInstructions", "xxx"); // 使用说明
// 消耗规则
JSONObject consumeRule = new JSONObject();
consumeRule.put("termsOfUse", new BigDecimal("10")); // 使用条件 满 x 元可用
consumeRule.put("maximumDiscountAmount", new BigDecimal("3")); // 最大优惠金额
consumeRule.put("explanationOfUnmetC 3onditions", "xxx"); // 不满足使用条件说明
consumeRule.put("validityPeriod", 48); // 自领取优惠券后有效时间,单位小时

责任链模式

现有代码的问题

  • 职责单一: 责任链模式可以将每个验证逻辑封装到一个独立的处理器中,每个处理器负责单一的验证职责,符合单一职责原则。

  • 可扩展性: 增加新的验证逻辑时,只需添加新的处理器,而不需要修改现有的代码。

  • 清晰的流程: 将所有验证逻辑组织在一起,使得代码结构更加清晰,易于理解。

什么是责任链模式

责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许将请求沿着一个处理链传递,直到链中的某个对象处理它。

核心部分代码:

@Component
public final class MerchantAdminChainContext<T> implements ApplicationContextAware, CommandLineRunner {

    private final Map<String, List<MerchantAdminAbstractChainHandler>> abstractChainHandlerContainer = new HashMap<>();
​
    /**
     * 责任链组件执行
     *
     * @param mark         责任链组件标识
     * @param requestParam 请求参数
     */
    public void handler(String mark, T requestParam) {
        // 根据 mark 标识从责任链容器中获取一组责任链实现 Bean 集合
        List<MerchantAdminAbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.get(mark);
        if (CollectionUtils.isEmpty(abstractChainHandlers)) {
            throw new RuntimeException(String.format("[%s] Chain of Responsibility ID is undefined.", mark));
        }
        abstractChainHandlers.forEach(each -> each.handler(requestParam));
    }
​
    @Override
    public void run(String... args) throws Exception {
        // 从 Spring IOC 容器中获取指定接口 Spring Bean 集合
        Map<String, MerchantAdminAbstractChainHandler> chainFilterMap = applicationContext.getBeansOfType(MerchantAdminAbstractChainHandler.class);
        chainFilterMap.forEach((beanName, bean) -> {
            // 判断 Mark 是否已经存在抽象责任链容器中,如果已经存在直接向集合新增;如果不存在,创建 Mark 和对应的集合
            List<MerchantAdminAbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.getOrDefault(bean.mark(), new ArrayList<>());
            abstractChainHandlers.add(bean);
            abstractChainHandlerContainer.put(bean.mark(), abstractChainHandlers);
        });
        abstractChainHandlerContainer.forEach((mark, unsortedChainHandlers) -> {
            // 对每个 Mark 对应的责任链实现类集合进行排序,优先级小的在前
            unsortedChainHandlers.sort(Comparator.comparing(Ordered::getOrder));
        });
    }
​
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

逻辑流程图

;