策略模式+工厂模式实现订单校验功能

本文以订单自动校验 为实战场景,从技术栈拆解、逐段代码解析、整体实现思路、完整代码整合、重点难点亮点优化点分析五个核心维度,详细讲解策略模式与工厂模式在实际项目中的融合运用,所有设计和代码均贴合企业生产级开发规范,可直接落地复用。

一、核心技术栈与设计模式拆解

本次订单校验系统以Spring Boot 为基础框架,核心融合策略模式工厂模式 ,辅以Java8+特性、工程化编码规范,所有技术和模式均服务于高扩展性、高可维护性、高稳定性的开发目标,先明确核心技术栈及设计模式的落地定位:

(一)基础开发技术

  1. Java8+ Stream流式编程:用于入参解析、规则筛选、结果聚合,简化循环代码,提升可读性和执行效率;
  2. Java并发容器 :使用ConcurrentHashMap实现执行器本地缓存,保证线程安全的同时提升获取效率;
  3. 异常分级处理:区分规则执行异常、空值异常等,实现"局部异常不影响全局"的容错设计;
  4. DTO/VO/PO分层模型:明确数据传输、业务配置、持久化的职责边界,避免数据混乱。

(二)Spring生态核心技术

  1. Spring Bean管理 :通过@Component将所有规则执行器、规则引擎纳入Spring容器,实现实例化和依赖管理;
  2. Bean动态获取 :通过SpringUtil.getBean(beanName)从容器中动态获取指定执行器,为"配置驱动规则"提供基础;
  3. 依赖注入 :通过@Resource/@Autowired实现组件之间的解耦注入,避免硬编码创建实例。

(三)核心设计模式:策略模式+工厂模式(融合运用)

本次场景是策略模式与工厂模式的经典融合落地,工厂模式作为策略模式的"调度桥梁",解决策略的动态获取问题,两者缺一不可,核心角色对应关系如下:

设计模式角色 订单校验系统实现类/接口 核心作用
策略模式-抽象策略 OrderCheckExecutor接口 定义所有订单校验规则的统一执行规范,是所有具体校验规则的"契约",约束实现标准
策略模式-具体策略 各类执行器(AmountCheckExecutor/StockCheckExecutor等) 实现抽象策略接口,封装单一校验规则的业务逻辑,每个类只负责一个校验维度,符合单一职责
工厂模式-简单工厂 OrderRuleEngine规则引擎 作为策略工厂,封装"根据规则配置动态获取具体执行器"的逻辑,向上层屏蔽执行器的创建、缓存、注入细节

(四)工程化编码规范

  1. 日志规范 :使用SLF4J+Logback,关键节点打印分级日志(info记录流程、error记录异常),包含核心标识(订单ID),方便问题追溯;
  2. 常量定义:所有硬编码内容(规则名称、类名、校验类型)均用常量定义,避免魔法值;
  3. 批量数据库操作 :使用saveOrUpdateBatch批量保存校验记录,减少数据库连接次数,提升性能;
  4. 工具类解耦:将纯业务逻辑封装为无依赖的工具类,与框架解耦,提升复用性和可测试性。

二、逐段代码深度解析

按"DTO/VO/PO数据层→抽象策略接口→具体策略实现→规则工具类→工厂模式(规则引擎)→核心业务服务"的顺序逐段解析,明确每部分代码的设计意图、与设计模式的关联、以及工程化考量。

(一)数据层:DTO/VO/PO(设计模式的基础数据载体)

1. 订单校验上下文DTO(OrderCheckDTO
java 复制代码
@Data
public class OrderCheckDTO {
    private Long orderId; // 订单ID(核心追溯标识)
    private Long userId; // 用户ID
    private Long productId; // 商品ID
    private BigDecimal orderAmount; // 订单金额
    private Integer buyNum; // 购买数量
    private String checkTypes; // 校验类型(逗号分割,如1,2,3,指定需要执行的规则)
    private UserInfo userInfo; // 用户信息(校验所需依赖数据)
    private ProductInfo productInfo; // 商品信息(校验所需依赖数据)
}

设计意图 :作为策略执行的统一上下文 ,封装所有校验规则需要的入参和依赖数据,让所有具体策略执行器的execute方法参数统一,符合策略模式"抽象方法参数标准化"的要求,避免不同执行器参数混乱。

2. 规则配置VO(OrderRuleVO
java 复制代码
@Data
public class OrderRuleVO {
    private Long id; // 规则ID
    private String ruleName; // 规则名称(日志/展示用)
    private String ruleClassName; // 规则类名(与Spring组件名一致,工厂获取执行器的关键)
    private String resource; // 校验类型(与checkTypes匹配,用于规则筛选)
}

设计意图 :作为策略配置的载体 ,存储规则的核心配置信息,尤其是ruleClassName,是连接"规则配置"和"具体策略执行器"的关键,实现"配置驱动策略"的核心基础,也是工厂模式能动态获取策略的前提。

3. 其他辅助VO/PO
java 复制代码
// 用户信息VO(封装用户相关校验数据)
@Data
public class UserInfo {
    private Long userId;
    private String userLevel; // 用户等级:VIP/NORMAL
    private BigDecimal amountLimit; // 下单金额限额
}

// 商品信息VO(封装商品相关校验数据)
@Data
public class ProductInfo {
    private Long productId;
    private Integer stock; // 库存
    private String productType; // 商品类型:HIGH_END/NORMAL
}

// 校验结果PO(与数据库表映射,持久化校验记录)
@Data
@TableName("t_order_check_record")
public class OrderCheckRecord {
    @TableId(type = IdType.AUTO)
    private Long id;
    private Long orderId; // 订单ID
    private Long ruleId; // 规则ID
    private String ruleName; // 规则名称
    private Boolean checkResult; // 校验结果:true=通过,false=不通过
    private String remark; // 执行备注(失败原因/通过说明)
    private LocalDateTime createTime; // 创建时间
}

// 通用执行结果VO(策略执行的统一返回值)
@Data
public class ExecuteResult {
    private Boolean result; // 执行结果:true=通过,false=不通过
    private String remark; // 执行备注
}

设计意图:通过分层模型明确数据职责,DTO负责流程间数据传输、VO负责业务配置/关联数据封装、PO负责持久化,避免数据混杂,同时让策略执行器的入参和返回值标准化。

(二)抽象策略接口:OrderCheckExecutor(策略模式核心)

java 复制代码
/**
 * 订单校验规则执行器抽象接口(策略模式-抽象策略)
 * 定义所有校验规则的统一执行规范,是所有具体策略的契约
 */
public interface OrderCheckExecutor {
    /**
     * 执行规则核心方法(所有具体策略必须实现的方法)
     * @param context 订单校验上下文,封装所有校验所需数据
     * @return 统一执行结果,包含是否通过和备注
     */
    ExecuteResult execute(OrderCheckDTO context);

    /**
     * 获取规则名称(日志/展示用)
     * @return 规则名称
     */
    String getRuleName();

    /**
     * 获取规则类名(与Spring组件名一致,工厂获取执行器的依据)
     * @return 规则类名
     */
    String getRuleClassName();

    /**
     * 获取当前执行器持有的规则配置(支持规则参数化扩展)
     * @return 订单规则VO
     */
    OrderRuleVO getRule();

    /**
     * 设置当前执行器的规则配置(由工厂注入)
     * @param rule 订单规则VO
     */
    void setRule(OrderRuleVO rule);
}

设计意图与模式关联

  1. 这是策略模式的核心抽象策略 ,定义了所有具体校验规则的统一执行规范 ,约束所有具体策略必须实现execute核心方法,同时标准化规则名称、类名的获取方式;
  2. 让上层业务代码只依赖接口,不依赖具体实现,彻底解除与具体校验规则的耦合,符合"面向接口编程"思想;
  3. 定义getRule/setRule方法,支持工厂将规则配置注入执行器,为后续规则参数化配置(如匹配阈值、白名单)预留扩展口;
  4. 统一execute方法的入参(OrderCheckDTO)和返回值(ExecuteResult),让上层代码能以统一的方式调用所有具体策略,无需关注不同规则的参数差异。

(三)具体策略实现:各类规则执行器(策略模式-具体策略)

所有具体执行器均实现OrderCheckExecutor接口,通过@Component纳入Spring容器,组件名与规则类名严格一致 ,封装单一校验维度的业务逻辑,符合"单一职责原则"。

1. 金额校验执行器(AmountCheckExecutor
java 复制代码
/**
 * 金额校验执行器:订单金额≤用户限额(策略模式-具体策略)
 * 组件名与ruleClassName一致:amountCheckExecutor
 */
@Slf4j
@Component("amountCheckExecutor")
public class AmountCheckExecutor implements OrderCheckExecutor {
    // 常量定义:避免魔法值,提升可维护性
    private static final String RULE_CLASS_NAME = "amountCheckExecutor";
    private static final String RULE_NAME = "订单金额校验规则";
    private OrderRuleVO rule; // 工厂注入的规则配置

    @Override
    public ExecuteResult execute(OrderCheckDTO context) {
        ExecuteResult result = new ExecuteResult();
        // 1. 从上下文中获取校验所需数据(统一入参,无需单独传参)
        BigDecimal orderAmount = context.getOrderAmount();
        BigDecimal amountLimit = context.getUserInfo().getAmountLimit();

        // 2. 调用工具类执行纯业务逻辑(与纯逻辑解耦,提升复用性)
        boolean isMatch = OrderCheckMatcher.isAmountMatch(orderAmount, amountLimit);
        result.setResult(isMatch);

        // 3. 封装标准化备注(日志/持久化用)
        if (isMatch) {
            result.setRemark(String.format("订单金额%s≤用户限额%s,校验通过", orderAmount, amountLimit));
        } else {
            result.setRemark(String.format("订单金额%s>用户限额%s,校验不通过", orderAmount, amountLimit));
        }
        log.info("订单{}:{}", context.getOrderId(), result.getRemark());
        return result;
    }

    // 实现接口的标准化方法,返回固定常量
    @Override
    public String getRuleName() {
        return RULE_NAME;
    }

    @Override
    public String getRuleClassName() {
        return RULE_CLASS_NAME;
    }

    // 规则配置的get/set,由工厂注入
    @Override
    public OrderRuleVO getRule() {
        return rule;
    }

    @Override
    public void setRule(OrderRuleVO rule) {
        this.rule = rule;
    }
}
2. 库存校验执行器(StockCheckExecutor
java 复制代码
/**
 * 库存校验执行器:购买数量≤商品库存(策略模式-具体策略)
 * 组件名与ruleClassName一致:stockCheckExecutor
 */
@Slf4j
@Component("stockCheckExecutor")
public class StockCheckExecutor implements OrderCheckExecutor {
    private static final String RULE_CLASS_NAME = "stockCheckExecutor";
    private static final String RULE_NAME = "商品库存校验规则";
    private OrderRuleVO rule;

    @Override
    public ExecuteResult execute(OrderCheckDTO context) {
        ExecuteResult result = new ExecuteResult();
        Integer buyNum = context.getBuyNum();
        Integer stock = context.getProductInfo().getStock();

        boolean isMatch = OrderCheckMatcher.isStockMatch(buyNum, stock);
        result.setResult(isMatch);
        if (isMatch) {
            result.setRemark(String.format("购买数量%s≤商品库存%s,校验通过", buyNum, stock));
        } else {
            result.setRemark(String.format("购买数量%s>商品库存%s,校验不通过", buyNum, stock));
        }
        log.info("订单{}:{}", context.getOrderId(), result.getRemark());
        return result;
    }

    @Override
    public String getRuleName() {
        return RULE_NAME;
    }

    @Override
    public String getRuleClassName() {
        return RULE_CLASS_NAME;
    }

    @Override
    public OrderRuleVO getRule() {
        return rule;
    }

    @Override
    public void setRule(OrderRuleVO rule) {
        this.rule = rule;
    }
}
3. 用户等级校验执行器(UserLevelCheckExecutor
java 复制代码
/**
 * 用户等级校验执行器:VIP用户才能购买高端商品(策略模式-具体策略)
 * 组件名与ruleClassName一致:userLevelCheckExecutor
 */
@Slf4j
@Component("userLevelCheckExecutor")
public class UserLevelCheckExecutor implements OrderCheckExecutor {
    private static final String RULE_CLASS_NAME = "userLevelCheckExecutor";
    private static final String RULE_NAME = "用户等级校验规则";
    private static final String VIP_LEVEL = "VIP";
    private static final String HIGH_END_PRODUCT = "HIGH_END";
    private OrderRuleVO rule;

    @Override
    public ExecuteResult execute(OrderCheckDTO context) {
        ExecuteResult result = new ExecuteResult();
        String userLevel = context.getUserInfo().getUserLevel();
        String productType = context.getProductInfo().getProductType();

        boolean isMatch = OrderCheckMatcher.isUserLevelMatch(userLevel, productType, VIP_LEVEL, HIGH_END_PRODUCT);
        result.setResult(isMatch);
        if (isMatch) {
            result.setRemark(String.format("用户等级%s,商品类型%s,校验通过", userLevel, productType));
        } else {
            result.setRemark(String.format("非VIP用户不能购买高端商品,用户等级%s,商品类型%s", userLevel, productType));
        }
        log.info("订单{}:{}", context.getOrderId(), result.getRemark());
        return result;
    }

    @Override
    public String getRuleName() {
        return RULE_NAME;
    }

    @Override
    public String getRuleClassName() {
        return RULE_CLASS_NAME;
    }

    @Override
    public OrderRuleVO getRule() {
        return rule;
    }

    @Override
    public void setRule(OrderRuleVO rule) {
        this.rule = rule;
    }
}

设计意图与模式关联

  1. 这是策略模式的具体策略 ,每个类只负责一个校验维度的业务逻辑(金额/库存/用户等级),符合"单一职责原则",便于维护和扩展;
  2. 所有具体策略均实现抽象策略接口,保证了执行标准的一致性,上层代码可通过抽象接口统一调用,无需关注具体实现细节;
  3. @Component注解的组件名与RULE_CLASS_NAME严格一致 ,这是工厂模式能从Spring容器动态获取执行器的核心前提
  4. 执行器只负责"数据获取+结果封装+调用工具类",不直接封装纯业务逻辑,将纯数据处理逻辑抽离到工具类,实现"策略执行"与"纯业务逻辑"的解耦;
  5. 常量定义规则名称、类名等硬编码内容,避免魔法值,提升代码可维护性;
  6. 持有OrderRuleVO对象,由工厂注入规则配置,为后续规则参数化配置预留扩展口(如从rule中获取匹配阈值)。

(四)规则工具类:OrderCheckMatcher(纯业务逻辑解耦)

java 复制代码
/**
 * 订单校验工具类:封装纯业务逻辑,与框架、策略模式完全解耦
 * 所有方法为静态方法,无需实例化,直接调用
 */
public class OrderCheckMatcher {
    /**
     * 金额校验纯逻辑:订单金额≤用户限额
     */
    public static boolean isAmountMatch(BigDecimal orderAmount, BigDecimal amountLimit) {
        if (orderAmount == null || amountLimit == null || orderAmount.compareTo(BigDecimal.ZERO) <= 0) {
            return false;
        }
        return orderAmount.compareTo(amountLimit) <= 0;
    }

    /**
     * 库存校验纯逻辑:购买数量≤商品库存
     */
    public static boolean isStockMatch(Integer buyNum, Integer stock) {
        if (buyNum == null || stock == null || buyNum <= 0 || stock < 0) {
            return false;
        }
        return buyNum <= stock;
    }

    /**
     * 用户等级校验纯逻辑:VIP用户才能购买高端商品,普通商品无限制
     */
    public static boolean isUserLevelMatch(String userLevel, String productType, String vipLevel, String highEndProduct) {
        if (userLevel == null || productType == null) {
            return false;
        }
        // 普通商品,所有用户可购买
        if (!highEndProduct.equals(productType)) {
            return true;
        }
        // 高端商品,仅VIP用户可购买
        return vipLevel.equals(userLevel);
    }
}

设计意图与工程化考量

  1. 解耦纯业务逻辑:将与框架、设计模式无关的纯数据处理逻辑封装到工具类,让策略执行器专注于"执行调度",工具类专注于"逻辑判断",符合单一职责;
  2. 提升复用性:若其他模块(如人工审核、订单复核)需要使用相同的校验逻辑,可直接调用工具类方法,无需重复编写;
  3. 提升可测试性:工具类是纯Java类,无任何框架依赖,可直接编写单元测试,无需启动Spring容器,测试效率高;
  4. 严格的空值处理:所有方法都做了入参空值校验,避免空指针异常,提升代码健壮性;
  5. 逻辑单一:每个方法只负责一个校验逻辑,无冗余代码,便于调试和修改。

(五)工厂模式:OrderRuleEngine规则引擎(策略工厂)

java 复制代码
/**
 * 订单规则引擎:策略模式的工厂类(简单工厂)
 * 核心职责:根据规则配置(OrderRuleVO)动态获取、缓存、注入具体策略执行器
 * 向上层屏蔽执行器的创建、获取、缓存细节
 */
@Component
@Slf4j
public class OrderRuleEngine {
    // 本地缓存:规则类名→执行器,ConcurrentHashMap保证线程安全
    // 避免每次获取执行器都从Spring容器查询,提升性能
    private final Map<String, OrderCheckExecutor> executorCache = new ConcurrentHashMap<>();

    /**
     * 工厂核心方法:根据规则配置获取具体策略执行器
     * @param rule 订单规则配置(含ruleClassName)
     * @return 具体策略执行器,null=未配置类名/执行器不存在
     */
    public OrderCheckExecutor getExecutor(OrderRuleVO rule) {
        // 1. 非空校验:规则未配置类名,直接返回null
        if (rule.getRuleClassName() == null || rule.getRuleClassName().isEmpty()) {
            log.info("订单规则{}未配置执行器类名,跳过执行", rule.getRuleName());
            return null;
        }

        // 2. 缓存优先:computeIfAbsent实现"缓存不存在则从Spring容器获取并缓存"
        return executorCache.computeIfAbsent(rule.getRuleClassName(), className -> {
            // 3. 动态获取Bean:根据类名(与@Component组件名一致)从Spring容器获取执行器
            OrderCheckExecutor executor = SpringUtil.getBean(className);
            if (executor != null) {
                // 4. 注入规则配置:将规则配置注入执行器,支持后续参数化扩展
                executor.setRule(rule);
                log.info("订单规则{}执行器{}加载成功并加入本地缓存", rule.getRuleName(), className);
            } else {
                log.error("订单规则{}执行器{}未在Spring容器中找到,跳过执行", rule.getRuleName(), className);
            }
            return executor;
        });
    }
}

设计意图与模式关联

  1. 这是工厂模式(简单工厂) 的核心实现,作为策略工厂 ,是连接"规则配置"和"具体策略执行器"的唯一桥梁
  2. 封装了"执行器获取+缓存+规则注入 "的全量逻辑,向上层业务代码屏蔽了所有细节,上层只需调用getExecutor(rule)即可获取执行器,无需关注"如何获取、是否缓存、如何注入配置";
  3. 使用ConcurrentHashMap实现执行器本地缓存,避免每次获取执行器都从Spring容器查询(Spring容器Bean获取有一定性能开销),提升执行效率,同时保证多线程环境下的线程安全;
  4. 通过SpringUtil.getBean(className)动态获取Spring Bean,核心前提是"执行器的@Component组件名与规则的ruleClassName一致",实现"配置驱动策略";
  5. 获取到执行器后,自动调用executor.setRule(rule)将规则配置注入执行器,为后续规则参数化配置预留扩展口;
  6. 完善的日志和异常处理,便于问题追溯(如执行器未找到、未配置类名等)。

(六)核心业务服务:OrderCheckService(策略模式的上层调用者)

java 复制代码
/**
 * 订单校验核心服务:策略模式的上层调用者
 * 核心职责:流程调度、规则筛选、策略执行、结果汇总、持久化
 * 不封装具体校验逻辑,只负责协调各组件,符合"总协调者"角色
 */
@Service
@Slf4j
public class OrderCheckService {
    @Resource
    private OrderRuleEngine orderRuleEngine; // 注入策略工厂
    @Resource
    private OrderCheckRecordService orderCheckRecordService; // 持久化服务
    // 模拟规则配置:实际项目中从数据库/配置中心(Nacos/Apollo)加载
    private final List<OrderRuleVO> allOrderRules = initOrderRules();

    /**
     * 订单自动校验主方法:上层统一调用入口
     * @param orderCheckDTO 订单校验上下文
     * @return 全局校验结果:true=所有规则通过,false=有规则失败
     */
    public boolean autoOrderCheck(OrderCheckDTO orderCheckDTO) {
        log.info("开始执行订单自动校验,订单ID:{}", orderCheckDTO.getOrderId());
        // 1. 入参解析:校验类型逗号分割→去空格→转List,支持多规则同时执行
        List<String> checkTypes = Arrays.stream(orderCheckDTO.getCheckTypes().split(","))
                .map(String::trim)
                .collect(Collectors.toList());

        // 2. 规则筛选:根据校验类型筛选需要执行的规则,减少无效执行
        List<OrderRuleVO> needExecuteRules = allOrderRules.stream()
                .filter(rule -> checkTypes.contains(rule.getResource()))
                .collect(Collectors.toList());
        log.info("订单{}需要执行的规则数:{},规则列表:{}", orderCheckDTO.getOrderId(), needExecuteRules.size(),
                needExecuteRules.stream().map(OrderRuleVO::getRuleName).collect(Collectors.joining(",")));

        // 3. 初始化变量:失败数、校验记录集、当前时间
        int failNum = 0;
        List<OrderCheckRecord> checkRecords = new ArrayList<>();
        LocalDateTime now = LocalDateTime.now();

        // 4. 遍历规则,执行策略
        for (OrderRuleVO rule : needExecuteRules) {
            // 初始化校验记录,用于持久化
            OrderCheckRecord record = initCheckRecord(orderCheckDTO, rule, now);
            // 4.1 工厂获取执行器:调用策略工厂,获取具体策略执行器
            OrderCheckExecutor executor = orderRuleEngine.getExecutor(rule);
            if (executor == null) {
                // 无执行器,默认标记为通过,记录备注
                record.setCheckResult(true);
                record.setRemark("规则未配置执行器,默认通过");
                checkRecords.add(record);
                continue;
            }

            try {
                // 4.2 执行策略:调用抽象策略的execute方法,执行具体校验逻辑
                // 上层只依赖接口,不依赖具体实现,符合面向接口编程
                ExecuteResult executeResult = executor.execute(orderCheckDTO);
                // 4.3 记录执行结果
                record.setCheckResult(executeResult.getResult());
                record.setRemark(executeResult.getRemark());
                checkRecords.add(record);
                // 4.4 统计失败数
                if (!executeResult.getResult()) {
                    failNum++;
                }
            } catch (Exception e) {
                // 5. 局部异常捕获:单个规则执行异常,不影响其他规则
                // 生产级容错设计:故障隔离
                log.error("订单{}规则{}执行异常", orderCheckDTO.getOrderId(), rule.getRuleName(), e);
                record.setCheckResult(false);
                record.setRemark("规则执行异常:" + e.getMessage());
                checkRecords.add(record);
                failNum++;
            }
        }

        // 6. 批量持久化:批量保存校验记录,减少数据库连接次数,提升性能
        orderCheckRecordService.saveOrUpdateBatch(checkRecords);
        log.info("订单{}校验完成,执行规则数:{},失败数:{}", orderCheckDTO.getOrderId(), needExecuteRules.size(), failNum);

        // 7. 结果汇总:无失败则全部通过,有失败则整体不通过
        boolean checkPass = failNum == 0;
        if (checkPass) {
            log.info("订单{}所有校验规则通过,允许下单", orderCheckDTO.getOrderId());
        } else {
            log.warn("订单{}有{}个校验规则失败,禁止下单", orderCheckDTO.getOrderId(), failNum);
        }
        return checkPass;
    }

    /**
     * 初始化校验记录:提取公共逻辑,减少代码冗余
     */
    private OrderCheckRecord initCheckRecord(OrderCheckDTO dto, OrderRuleVO rule, LocalDateTime now) {
        OrderCheckRecord record = new OrderCheckRecord();
        record.setOrderId(dto.getOrderId());
        record.setRuleId(rule.getId());
        record.setRuleName(rule.getRuleName());
        record.setCreateTime(now);
        return record;
    }

    /**
     * 初始化规则配置:模拟从数据库/配置中心加载,实际项目中可替换为持久化查询
     */
    private List<OrderRuleVO> initOrderRules() {
        List<OrderRuleVO> rules = new ArrayList<>();
        // 金额校验规则
        OrderRuleVO amountRule = new OrderRuleVO();
        amountRule.setId(1L);
        amountRule.setRuleName("订单金额校验规则");
        amountRule.setRuleClassName("amountCheckExecutor");
        amountRule.setResource("1");
        rules.add(amountRule);
        // 库存校验规则
        OrderRuleVO stockRule = new OrderRuleVO();
        stockRule.setId(2L);
        stockRule.setRuleName("商品库存校验规则");
        stockRule.setRuleClassName("stockCheckExecutor");
        stockRule.setResource("2");
        rules.add(stockRule);
        // 用户等级校验规则
        OrderRuleVO levelRule = new OrderRuleVO();
        levelRule.setId(3L);
        levelRule.setRuleName("用户等级校验规则");
        levelRule.setRuleClassName("userLevelCheckExecutor");
        levelRule.setResource("3");
        rules.add(levelRule);
        return rules;
    }
}

设计意图与模式关联

  1. 这是策略模式的上层调用者 ,作为整个订单校验流程的总协调者,只负责"流程调度、规则筛选、策略执行、结果汇总、持久化",不封装任何具体的校验逻辑,符合"单一职责原则";
  2. 通过注入策略工厂(OrderRuleEngine) 获取具体策略执行器,不直接依赖任何具体策略实现类,彻底解除与具体校验规则的耦合,新增/删除规则无需修改此类代码;
  3. 实现"配置驱动执行 ":通过checkTypes入参筛选需要执行的规则,结合工厂模式动态获取执行器,实现"指定哪些规则就执行哪些规则",灵活性极高;
  4. 局部异常捕获:单个规则执行异常时,仅标记该规则失败,继续执行其他规则,实现"故障隔离",符合生产级系统的容错设计要求;
  5. 性能优化细节:使用Stream流式编程筛选规则、批量保存数据库记录、工厂层的执行器缓存,多维度提升系统性能;
  6. 日志规范:关键节点打印含订单ID的日志,方便问题追溯,日志级别区分清晰(info/error/warn);
  7. 代码复用 :提取initCheckRecord私有方法封装公共逻辑,减少代码冗余;
  8. 可扩展 :规则配置从initOrderRules模拟加载,实际项目中可轻松替换为从数据库/配置中心(Nacos/Apollo)加载,支持规则配置的动态更新。

三、整体实现思路:策略模式+工厂模式融合执行闭环

将所有组件串联,梳理从"发起订单校验"到"返回校验结果"的完整执行闭环 ,明确策略模式与工厂模式在各环节的作用,以及组件之间的协作关系,核心思路可总结为"配置驱动→工厂调度→策略执行→结果汇总"。

步骤1:前置准备 - 规则配置与Spring容器初始化

  1. 规则配置 :所有订单校验规则(OrderRuleVO)提前配置在数据库/配置中心,每个规则指定唯一的ruleClassName(与Spring组件名一致);
  2. Spring容器初始化 :所有具体策略执行器(AmountCheckExecutor等)通过@Component纳入Spring容器,组件名与ruleClassName严格一致;
  3. 工厂初始化OrderRuleEngine作为Spring组件初始化,创建空的执行器本地缓存(ConcurrentHashMap)。

步骤2:请求入口 - 入参解析与规则筛选

  1. 外部系统调用OrderCheckService.autoOrderCheck(OrderCheckDTO),传入订单信息、校验类型(checkTypes,如1,2,3);
  2. 解析checkTypes为List,从规则配置中筛选出需要执行的规则 (根据resource字段匹配),减少无效执行;
  3. 初始化失败数、校验记录集等基础变量。

步骤3:工厂调度 - 动态获取具体策略执行器

  1. 遍历筛选后的每个规则(OrderRuleVO),调用策略工厂(OrderRuleEngine)getExecutor(rule)方法;
  2. 工厂先校验规则类名是否为空,非空则优先从本地缓存获取执行器,缓存不存在则从Spring容器动态获取;
  3. 工厂将规则配置注入执行器,返回具体策略执行器给上层业务服务。

步骤4:策略执行 - 统一调用抽象策略方法

  1. 上层业务服务通过抽象策略接口(OrderCheckExecutor) 调用execute(OrderCheckDTO)方法,执行具体校验逻辑;
  2. 具体策略执行器从上下文中获取所需数据,调用纯业务逻辑工具类(OrderCheckMatcher) 完成校验;
  3. 执行器封装标准化的执行结果(ExecuteResult),返回给上层业务服务。

步骤5:结果处理 - 局部结果记录与全局结果汇总

  1. 上层业务服务记录单个规则的执行结果,持久化到校验记录集;
  2. 若规则执行失败/异常,统计失败数;单个规则异常仅局部处理,不影响其他规则执行;
  3. 所有规则执行完成后,根据失败数汇总全局结果:失败数=0则全部通过,否则整体不通过。

步骤6:持久化与返回 - 批量保存与结果响应

  1. 批量保存所有校验记录到数据库,减少数据库连接次数;
  2. 返回全局校验结果(true/false),供外部系统判断是否允许下单;
  3. 打印校验完成日志,包含核心统计信息(执行规则数、失败数)。

核心组件协作关系(策略模式+工厂模式)

复制代码
外部系统 → 上层调用者(OrderCheckService)→ 策略工厂(OrderRuleEngine)→ 抽象策略(OrderCheckExecutor)→ 具体策略(XXXExecutor)→ 纯逻辑工具类(OrderCheckMatcher)
                                                                 ↓
上层调用者 ←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←← 执行结果
        ↓
持久化服务(OrderCheckRecordService)→ 数据库

核心特点 :所有组件单向依赖、职责明确、无循环依赖,符合"高内聚、低耦合"的设计原则;上层代码仅依赖抽象,不依赖具体实现,完美体现面向接口编程思想。

四、完整代码整合(可直接运行,基于Spring Boot)

将以上所有代码按组件类型整理,包含完整的依赖说明、核心代码、测试代码,可直接在Spring Boot项目中运行测试。

(一)项目依赖(pom.xml核心依赖)

xml 复制代码
<!-- Spring Boot核心 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- MyBatis-Plus(持久化) -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3.1</version>
</dependency>
<!-- Lombok(简化代码) -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<!-- 数据库驱动(MySQL) -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<!-- Spring Boot测试 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

(二)核心工具类(SpringUtil:动态获取Bean)

java 复制代码
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * Spring容器工具类:实现ApplicationContextAware,获取Spring容器上下文
 * 用于动态获取Bean实例
 */
@Component
public class SpringUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringUtil.applicationContext = applicationContext;
    }

    /**
     * 根据Bean名称动态获取Bean实例
     * @param beanName Bean名称(与@Component注解的名称一致)
     * @param <T> Bean类型
     * @return Bean实例
     */
    public static <T> T getBean(String beanName) {
        if (applicationContext == null) {
            return null;
        }
        return (T) applicationContext.getBean(beanName);
    }
}

(三)完整业务代码(按包结构整理)

复制代码
com.order.check
├── dto/
│   ├── OrderCheckDTO.java        // 订单校验上下文DTO
│   ├── UserInfo.java             // 用户信息VO
│   ├── ProductInfo.java          // 商品信息VO
│   └── ExecuteResult.java        // 通用执行结果VO
├── vo/
│   └── OrderRuleVO.java          // 规则配置VO
├── po/
│   └── OrderCheckRecord.java     // 校验结果PO
├── executor/                     // 具体策略执行器包
│   ├── OrderCheckExecutor.java   // 抽象策略接口
│   ├── AmountCheckExecutor.java  // 金额校验执行器
│   ├── StockCheckExecutor.java   // 库存校验执行器
│   └── UserLevelCheckExecutor.java // 用户等级校验执行器
├── matcher/
│   └── OrderCheckMatcher.java    // 纯业务逻辑工具类
├── engine/
│   └── OrderRuleEngine.java      // 策略工厂(规则引擎)
├── service/                      // 业务服务层
│   ├── OrderCheckService.java    // 核心业务服务(上层调用者)
│   └── OrderCheckRecordService.java // 持久化服务(MyBatis-Plus实现)
└── test/
    └── OrderCheckTest.java       // 测试类

说明 :以上所有类的代码均为前文逐段解析的完整代码,直接复制即可;OrderCheckRecordService为MyBatis-Plus常规服务,继承IService<OrderCheckRecord>即可,无需额外编写代码。

(四)测试代码(SpringBootTest)

java 复制代码
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.order.check.dto.OrderCheckDTO;
import com.order.check.dto.ProductInfo;
import com.order.check.dto.UserInfo;
import com.order.check.service.OrderCheckService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;

/**
 * 订单校验测试类:验证策略模式+工厂模式的完整执行流程
 */
@SpringBootTest
public class OrderCheckTest {
    @Autowired
    private OrderCheckService orderCheckService;

    @Test
    public void testSuccessOrderCheck() {
        // 1. 构建测试上下文:VIP用户+高端商品+金额≤限额+库存充足
        OrderCheckDTO dto = new OrderCheckDTO();
        dto.setOrderId(10001L);
        dto.setUserId(20001L);
        dto.setProductId(30001L);
        dto.setOrderAmount(new BigDecimal("5000")); // 订单金额5000
        dto.setBuyNum(2); // 购买2件
        dto.setCheckTypes("1,2,3"); // 执行金额、库存、用户等级校验

        // 构建用户信息:VIP用户,金额限额10000
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(20001L);
        userInfo.setUserLevel("VIP");
        userInfo.setAmountLimit(new BigDecimal("10000"));
        dto.setUserInfo(userInfo);

        // 构建商品信息:高端商品,库存5
        ProductInfo productInfo = new ProductInfo();
        productInfo.setProductId(30001L);
        productInfo.setProductType("HIGH_END");
        productInfo.setStock(5);
        dto.setProductInfo(productInfo);

        // 2. 执行订单校验
        boolean checkPass = orderCheckService.autoOrderCheck(dto);

        // 3. 断言结果:应该通过
        Assert.isTrue(checkPass, "VIP用户符合所有校验规则,应该通过");
        System.out.println("测试结果:订单校验通过,符合预期");
    }

    @Test
    public void testFailOrderCheck() {
        // 1. 构建测试上下文:普通用户+高端商品(用户等级校验失败)
        OrderCheckDTO dto = new OrderCheckDTO();
        dto.setOrderId(10002L);
        dto.setUserId(20002L);
        dto.setProductId(30001L);
        dto.setOrderAmount(new BigDecimal("3000"));
        dto.setBuyNum(1);
        dto.setCheckTypes("1,2,3");

        // 构建用户信息:普通用户
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(20002L);
        userInfo.setUserLevel("NORMAL");
        userInfo.setAmountLimit(new BigDecimal("5000"));
        dto.setUserInfo(userInfo);

        // 构建商品信息:高端商品
        ProductInfo productInfo = new ProductInfo();
        productInfo.setProductId(30001L);
        productInfo.setProductType("HIGH_END");
        productInfo.setStock(10);
        dto.setProductInfo(productInfo);

        // 2. 执行订单校验
        boolean checkPass = orderCheckService.autoOrderCheck(dto);

        // 3. 断言结果:应该失败
        Assert.isFalse(checkPass, "普通用户购买高端商品,应该失败");
        System.out.println("测试结果:订单校验失败,符合预期");
    }
}

(五)测试结果

1. 成功用例测试结果
复制代码
开始执行订单自动校验,订单ID:10001
订单10001需要执行的规则数:3,规则列表:订单金额校验规则,商品库存校验规则,用户等级校验规则
订单规则订单金额校验规则执行器amountCheckExecutor加载成功并加入本地缓存
订单10001:订单金额5000≤用户限额10000,校验通过
订单规则商品库存校验规则执行器stockCheckExecutor加载成功并加入本地缓存
订单10001:购买数量2≤商品库存5,校验通过
订单规则用户等级校验规则执行器userLevelCheckExecutor加载成功并加入本地缓存
订单10001:用户等级VIP,商品类型HIGH_END,校验通过
订单10001校验完成,执行规则数:3,失败数:0
订单10001所有校验规则通过,允许下单
测试结果:订单校验通过,符合预期
2. 失败用例测试结果
复制代码
开始执行订单自动校验,订单ID:10002
订单10002需要执行的规则数:3,规则列表:订单金额校验规则,商品库存校验规则,用户等级校验规则
订单规则订单金额校验规则执行器amountCheckExecutor加载成功并加入本地缓存
订单10002:订单金额3000≤用户限额5000,校验通过
订单规则商品库存校验规则执行器stockCheckExecutor加载成功并加入本地缓存
订单10002:购买数量1≤商品库存10,校验通过
订单规则用户等级校验规则执行器userLevelCheckExecutor加载成功并加入本地缓存
订单10002:非VIP用户不能购买高端商品,用户等级NORMAL,商品类型HIGH_END
订单10002校验完成,执行规则数:3,失败数:1
订单10002有1个校验规则失败,禁止下单
测试结果:订单校验失败,符合预期

五、重点、难点、亮点、优化点分析

结合企业生产级开发要求,从策略模式+工厂模式融合运用的角度,分析本次订单校验系统的核心重点、实现难点、设计亮点和可优化方向,为后续项目落地和迭代提供参考。

(一)核心重点:必须掌握的设计与实现要点

  1. 策略模式的标准三层落地:抽象策略(接口)→具体策略(执行器)→策略工厂(规则引擎),三层结构清晰,职责划分明确,是本次实现的核心骨架,也是企业中策略模式的经典落地方式;
  2. 配置驱动策略的核心衔接OrderRuleVOruleClassName与具体策略执行器的@Component组件名严格一致,这是工厂模式能动态获取执行器的关键,也是"配置驱动"的核心前提;
  3. 面向接口编程的极致体现:上层业务服务仅依赖抽象策略接口和策略工厂,不依赖任何具体策略实现类,新增/删除规则无需修改核心代码,彻底解除耦合;
  4. 工厂模式的缓存与注入设计 :策略工厂不仅负责获取执行器,还实现了执行器的本地线程安全缓存规则配置注入,既提升性能,又为后续扩展预留口;
  5. 标准化的入参和返回值 :所有具体策略的execute方法入参统一为OrderCheckDTO,返回值统一为ExecuteResult,保证了上层调用的一致性,避免参数混乱。

(二)实现难点:理解与落地的关键卡点

  1. 策略模式与工厂模式的融合边界:明确"抽象策略负责定义规范、具体策略负责实现逻辑、工厂模式负责调度获取"的边界,避免工厂模式承担过多业务逻辑,或具体策略依赖工厂模式;
  2. 动态Bean获取的原理与前提 :理解SpringUtil.getBean(beanName)的底层原理(Spring容器的Bean注册表),以及"组件名与规则类名一致"的必要性,若两者不一致会直接导致执行器获取失败;
  3. 执行器的线程安全与缓存设计 :工厂模式中使用ConcurrentHashMap作为执行器缓存,而非普通HashMap,需理解多线程环境下的线程安全问题,以及computeIfAbsent方法的原子性;
  4. 容错设计的度的把握:单个规则执行异常时,选择"标记失败并继续执行其他规则"而非"中断整个流程",需结合业务场景把握容错设计的度,既保证系统稳定性,又符合业务需求;
  5. 规则配置与业务逻辑的解耦:将纯业务逻辑抽离到工具类,避免具体策略执行器中混杂框架代码和纯逻辑代码,需理解"解耦"的核心目的是提升复用性和可测试性。

(三)设计亮点:贴合企业生产级的工程化思维

  1. 极致的扩展性(符合开闭原则) :新增校验规则仅需3步(实现抽象接口+添加@Component注解+配置规则类名),无需修改任何核心代码,完美符合"对扩展开放、对修改关闭"的开闭原则,这是企业级代码的核心标准;
  2. 生产级的容错与稳定性设计
    • 局部异常捕获,实现故障隔离,单个规则失败不影响全局;
    • 严格的空值校验(工具类、执行器、工厂均做了空值处理),避免空指针异常;
    • 跳过未配置执行器的规则,避免无效执行和空指针;
  3. 多维度的性能优化
    • 工厂层的执行器本地缓存,避免重复从Spring容器获取Bean;
    • Stream流式编程简化循环,提升代码执行效率;
    • 批量保存数据库记录,减少数据库连接次数;
    • 规则筛选机制,减少无效规则的执行;
  4. 清晰的分层与职责划分:DTO/VO/PO分层、策略接口与具体实现分离、执行器与纯逻辑工具类分离,每个组件只负责一个核心功能,无职责重叠,便于团队协作和维护;
  5. 工程化的编码规范
    • 常量定义所有硬编码内容,避免魔法值;
    • 语义化的命名(类名/方法名/变量名),无需注释即可理解作用;
    • 关键节点打印含核心标识(订单ID)的分级日志,方便问题追溯;
    • 提取公共方法(如initCheckRecord),减少代码冗余;
  6. 预留扩展口,兼顾当前与未来
    • 执行器持有OrderRuleVO配置对象,为后续规则参数化配置(如匹配阈值、白名单)预留扩展口;
    • 规则配置从模拟方法加载,可轻松替换为数据库/配置中心加载,支持规则动态更新;
    • 抽象策略接口定义getRule/setRule方法,为后续复杂规则配置预留扩展口。

(四)优化点:生产级项目的迭代方向

本次实现已满足企业基本生产要求,以下优化点为生产级项目的进阶迭代方向,可根据业务复杂度和性能要求逐步实现:

  1. 规则配置动态化 :将规则配置从模拟方法/数据库迁移到配置中心(Nacos/Apollo),添加配置监听,实现规则配置的动态更新(新增/修改/删除规则无需重启服务);
  2. 规则参数化配置 :扩展OrderRuleVO,增加Map<String, String> configParams字段,支持配置规则参数(如金额校验的阈值、用户等级的白名单),执行器从rule中获取参数,让规则更灵活,无需修改代码即可调整逻辑;
  3. 执行器的异步执行 :若规则之间无依赖关系,将规则执行改为异步执行(CompletableFuture),所有规则异步执行完成后汇总结果,提升多规则执行的并发性能,减少总耗时;
  4. 缓存防护机制 :若规则配置从Redis缓存加载(而非本地模拟),增加缓存穿透、缓存击穿、缓存雪崩的防护措施(布隆过滤器、分布式锁、随机过期时间);
  5. 异常分级处理:将异常分为"严重异常"(如数据库连接失败、配置中心不可用)和"普通异常"(如数据格式错误),严重异常中断当前订单校验,普通异常仅标记规则失败,提升容错的精细化;
  6. 执行结果标准化扩展 :扩展ExecuteResult,增加"规则编码、执行时间、错误码、错误类型"等字段,丰富执行结果信息,便于性能分析、问题排查和前端展示;
  7. 接入限流熔断组件 :若校验规则依赖第三方接口(如库存查询、用户等级查询),接入Sentinel/Resilience4j,实现限流、熔断、降级,避免第三方接口异常影响订单校验系统;
  8. 单元测试全覆盖:为工具类、执行器、工厂模式编写完整的单元测试,覆盖所有分支场景(如空值、成功、失败、异常),提升代码的可测试性和稳定性;
  9. 规则执行的灰度发布 :在OrderRuleVO中增加grayRatio(灰度比例)和grayUserIds(灰度用户白名单)字段,支持规则的灰度发布,逐步上线新规则,降低业务风险;
  10. 主方法代码拆分 :若后续规则数量增加,autoOrderCheck方法代码会变长,可将"入参解析、规则筛选、结果汇总"拆分为独立的私有方法,让主方法更简洁,便于维护。

六、总结

本次订单校验系统是策略模式与工厂模式在企业项目中融合运用的经典实战 ,核心价值不在于代码本身,而在于背后的设计思想和工程化思维

  1. 策略模式解决"多规则执行的解耦与扩展"问题:通过抽象策略定义统一规范,让具体规则实现类相互独立,新增规则无需修改核心代码,符合开闭原则;
  2. 工厂模式解决"策略的动态获取与调度"问题:封装策略的获取、缓存、注入细节,向上层屏蔽底层实现,让上层代码专注于流程调度,无需关注策略的创建和获取;
  3. 工程化思维保证代码的生产级可用性:从扩展性、稳定性、性能、可维护性、可测试性多维度设计代码,贴合企业实际开发要求,可直接落地复用;
  4. 面向接口编程是核心基础:所有组件之间通过接口交互,上层仅依赖抽象,不依赖具体实现,彻底解除耦合,这是所有设计模式落地的核心前提。

这种"策略模式+工厂模式"的融合设计,不仅适用于订单校验场景,还可广泛应用于风控规则引擎、权限验证、数据校验、消息推送等所有"多规则执行、需要灵活扩展"的业务场景,是Java后端开发中必须掌握的核心设计思路。

相关推荐
短剑重铸之日2 小时前
《设计模式》第五篇:策略模式
java·后端·设计模式·策略模式
知行合一。。。2 小时前
Linux--10---crontab -e定时任务
java·linux·运维
cyforkk2 小时前
16、Java 基础硬核复习:网络编程的核心逻辑与面试考点
java·网络·面试
帅得不敢出门2 小时前
Android定位RK编译的system.img比MTK大350M的原因
android·framework·策略模式
serve the people2 小时前
python环境搭建 (五) Dockerfile 和 docker-compose.yml 核心作用
java·python·docker
独断万古他化2 小时前
【Spring 事务】核心概念与实战:从手动控制到注解自动事务
java·spring·事务
马猴烧酒.2 小时前
【团队空间|第十一天】基础功能实现,RBAC权限控制,ShardingSphere详解
java·开发语言·数据库
fengxin_rou2 小时前
从 String 到 Zset:Redis 核心数据结构全解析及排行榜应用
java·开发语言·redis·多线程
世界尽头与你2 小时前
CVE-2025-55752_ Apache Tomcat 安全漏洞
java·安全·网络安全·渗透测试·tomcat·apache