【设计模式】Java规则树重构复杂业务逻辑
前言
一、规则树核心概念与设计原理
1.1 规则树的基本概念
1.2 规则树的类型与适用场景
二、核心代码实现
2.1 StrategyHandler 策略处理接口
2.2 StrategyMapper 策略映射器
2.3 AbstractStrategyRouter 策略路由抽象类
2.4 AbstractMultiThreadStrategyRouter 异步资源加载策略抽象类
三、规则树效果测试
3.1 DefaultStrategyFactory 默认策略工厂
3.2 AbstractSupport 规则树抽象支持类
3.3 RootNode 根节点策略处理器
3.4 SwitchRoot 开关节点策略处理器
3.5 AccountNode 账户节点策略处理器
3.6 MemberLevelNode1 会员级别1节点策略处理器
3.7 MemberLevelNode2 会员级别2节点策略处理器
3.8 Test 规则树测试类
3.9 测试结果
四、总结
前言
随着企业数字化转型的深入,业务逻辑变得越来越复杂且多变。以电商平台为例,一个简单的优惠券计算可能涉及数十个条件:用户等级、商品品类、订单金额、促销活动、库存状态、时间周期等。传统的编程方式通常使用大量的if-else或switch-case语句来处理这些规则,导致代码出现以下问题:
代码臃肿:一个方法可能包含数百行的条件判断
难以维护:每次业务规则变更都需要修改代码并重新部署
耦合度高:业务规则与核心逻辑紧密耦合,无法独立变化
可读性差:复杂的嵌套条件让新同事难以理解业务逻辑
测试困难:覆盖所有条件分支需要编写大量测试用例
规则树模式(Rule Tree Pattern) 正是为了解决这些问题而生的。它将复杂的业务规则抽象为树形结构,通过节点之间的组合关系来表达业务逻辑,实现了业务规则与核心流程的解耦,让系统能够快速响应业务变化。
一、规则树核心概念与设计原理
1.1 规则树的基本概念
规则树是一种树形数据结构,用于表示和执行复杂的业务规则。它由以下核心组件构成:
根节点(Root Node):规则的入口点,整个规则树的起点
条件节点(Condition Node):负责评估特定条件,决定执行路径
动作节点(Action Node):执行具体的业务操作或返回结果
组合节点(Composite Node):包含子节点,控制执行逻辑(与、或、非等)
叶子节点(Leaf Node):没有子节点的终端节点,通常是动作节点
1.2 规则树的类型与适用场景
根据不同的业务需求,规则树可以分为多种类型:
类型 | 特点 | 适用场景 |
---|---|---|
决策树 | 每个节点代表一个决策点,路径清晰 | 分类问题、风险评估 |
行为树 | 关注节点执行和行为控制 | 游戏AI、工作流引擎 |
表达式树 | 将数学表达式转化为树结构 | 计算规则、定价引擎 |
组合规则树 | 支持复杂的逻辑组合 | 风控系统、合规检查 |
二、核心代码实现
2.1 StrategyHandler 策略处理接口
StrategyHandler 是一个泛型接口,定义了策略处理的核心方法。它包含一个默认实现,当没有匹配的策略时使用默认处理。该接口的泛型参数包括请求参数类型(T)、动态上下文类型(D)和返回结果类型(R)。
/*** @description 受理策略处理* T 入参类型* D 上下文参数* R 返参类型*/
public interface StrategyHandler<T, D, R> {StrategyHandler DEFAULT = (T, D) -> null;R apply(T requestParameter, D dynamicContext) throws Exception;}
2.2 StrategyMapper 策略映射器
StrategyMapper 是一个泛型接口,用于根据请求参数和动态上下文获取待执行的策略处理器。它定义了一个方法,根据传入的参数返回对应的策略处理器。
/*** @description 策略映射器* T 入参类型* D 上下文参数* R 返参类型*/
public interface StrategyMapper<T, D, R> {/*** 获取待执行策略** @param requestParameter 入参* @param dynamicContext 上下文* @return 返参* @throws Exception 异常*/StrategyHandler<T, D, R> get(T requestParameter, D dynamicContext) throws Exception;}
2.3 AbstractStrategyRouter 策略路由抽象类
AbstractStrategyRouter 是一个抽象类,结合了策略处理器和策略映射器的功能,提供了灵活的策略路由机制。它实现了 StrategyMapper 和 StrategyHandler 接口,兼具映射和执行能力。该类还提供了一个默认策略处理器,当没有匹配的策略时使用默认处理。
import lombok.Getter;
import lombok.Setter;/*** 策略路由抽象类* 结合策略处理器和策略映射器的功能,提供灵活的策略路由机制* * 功能说明:* 1. 实现策略路由的核心逻辑,根据请求参数和上下文选择合适的策略处理器* 2. 提供默认策略处理器,当没有匹配的策略时使用默认处理* 3. 同时实现StrategyMapper和StrategyHandler接口,兼具映射和执行能力* * 泛型参数说明:* - T: 请求参数类型(Request Parameter Type)* - D: 动态上下文类型(Dynamic Context Type) * - R: 返回结果类型(Return Result Type)*/
public abstract class AbstractStrategyRouter<T, D, R> implements StrategyMapper<T, D, R>, StrategyHandler<T, D, R> {/*** 默认策略处理器* 当没有找到匹配的策略处理器时使用该默认处理器* 使用Lombok注解自动生成getter和setter方法*/@Getter@Setterprotected StrategyHandler<T, D, R> defaultStrategyHandler = StrategyHandler.DEFAULT;/*** 策略路由方法* 根据请求参数和动态上下文选择合适的策略处理器并执行* * @param requestParameter 请求参数* @param dynamicContext 动态上下文,包含执行过程中的共享数据* @return 策略处理器的执行结果* @throws Exception 策略执行过程中可能抛出的异常*/public R router(T requestParameter, D dynamicContext) throws Exception {// 1. 获取匹配的策略处理器StrategyHandler<T, D, R> strategyHandler = get(requestParameter, dynamicContext);// 2. 如果找到匹配的策略处理器,则执行该策略if(null != strategyHandler) {return strategyHandler.apply(requestParameter, dynamicContext);}// 3. 如果没有找到匹配的策略,则使用默认策略处理器return defaultStrategyHandler.apply(requestParameter, dynamicContext);}}
2.4 AbstractMultiThreadStrategyRouter 异步资源加载策略抽象类
bstractMultiThreadStrategyRouter 扩展了基础策略路由,支持多线程异步数据加载和业务处理分离。它提供了异步数据加载框架,在执行业务逻辑前预先加载所需资源,从而提高系统性能和响应速度。
import lombok.Getter;
import lombok.Setter;import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;/*** 异步资源加载策略路由抽象类* 扩展基础策略路由,支持多线程异步数据加载和业务处理分离* * 功能说明:* 1. 提供异步数据加载框架,在执行业务逻辑前预先加载所需资源* 2. 分离数据加载和业务处理,提高系统性能和响应速度* 3. 支持多线程并发执行,优化资源利用率* * 泛型参数说明:* - T: 请求参数类型(Request Parameter Type)* - D: 动态上下文类型(Dynamic Context Type) * - R: 返回结果类型(Return Result Type)*/
public abstract class AbstractMultiThreadStrategyRouter<T, D, R> implements StrategyMapper<T, D, R>, StrategyHandler<T, D, R> {/*** 默认策略处理器* 当没有找到匹配的策略处理器时使用该默认处理器*/@Getter@Setterprotected StrategyHandler<T, D, R> defaultStrategyHandler = StrategyHandler.DEFAULT;/*** 策略路由方法* 根据请求参数和动态上下文选择合适的策略处理器并执行* * @param requestParameter 请求参数* @param dynamicContext 动态上下文* @return 策略处理器的执行结果* @throws Exception 执行过程中可能抛出的异常*/public R router(T requestParameter, D dynamicContext) throws Exception {// 1. 获取匹配的策略处理器StrategyHandler<T, D, R> strategyHandler = get(requestParameter, dynamicContext);// 2. 如果找到匹配的策略处理器,则执行该策略if(null != strategyHandler) {return strategyHandler.apply(requestParameter, dynamicContext);}// 3. 如果没有找到匹配的策略,则使用默认策略处理器return defaultStrategyHandler.apply(requestParameter, dynamicContext);}/*** 策略执行方法(模板方法)* 定义异步加载+业务处理的执行流程* * @param requestParameter 请求参数* @param dynamicContext 动态上下文* @return 业务处理结果* @throws Exception 执行过程中可能抛出的异常*/@Overridepublic R apply(T requestParameter, D dynamicContext) throws Exception {// 第一阶段:异步加载数据(多线程执行)multiThread(requestParameter, dynamicContext);// 第二阶段:业务流程受理(单线程执行)return doApply(requestParameter, dynamicContext);}/*** 异步数据加载方法(抽象方法)* 子类需要实现具体的多线程数据加载逻辑* * @param requestParameter 请求参数* @param dynamicContext 动态上下文* @throws ExecutionException 执行异常* @throws InterruptedException 线程中断异常* @throws TimeoutException 超时异常*/protected abstract void multiThread(T requestParameter, D dynamicContext) throws ExecutionException, InterruptedException, TimeoutException;/*** 业务流程处理方法(抽象方法)* 子类需要实现具体的业务逻辑* * @param requestParameter 请求参数* @param dynamicContext 动态上下文* @return 业务处理结果* @throws Exception 业务处理过程中可能抛出的异常*/protected abstract R doApply(T requestParameter, D dynamicContext) throws Exception;}
三、规则树效果测试
3.1 DefaultStrategyFactory 默认策略工厂
DefaultStrategyFactory 是一个策略工厂类,负责创建和管理策略处理器,提供策略模式的统一入口。它维护策略执行的上下文信息,支持数据在不同策略节点间传递。
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Service;import java.util.HashMap;
import java.util.Map;/*** 默认策略工厂* 负责创建和管理策略处理器,提供策略模式的统一入口** 功能说明:* 1. 作为策略模式的工厂类,提供策略处理器的获取* 2. 维护策略执行的上下文信息,支持数据在不同策略节点间传递* 3. 使用Spring Service注解,作为单例Bean管理*/
@Service
public class DefaultStrategyFactory {// 根节点处理器,作为策略链的起点private final RootNode rootNode;/*** 构造函数,通过依赖注入初始化根节点* @param rootNode 根节点策略处理器*/public DefaultStrategyFactory(RootNode rootNode) {this.rootNode = rootNode;}/*** 获取策略处理器* @return 根节点策略处理器,作为整个策略链的入口*/public StrategyHandler<String, DynamicContext, String> strategyHandler() {return rootNode;}/*** 动态上下文类* 用于在策略执行过程中传递和共享数据** 功能特点:* - 使用泛型支持不同类型的数据存储和获取* - 基于HashMap实现键值对存储* - 支持层级管理(level字段)* - 使用Lombok注解简化代码*/@Data@Builder@AllArgsConstructor@NoArgsConstructorpublic static class DynamicContext {/*** 执行层级,可用于控制策略执行的深度或阶段*/private int level;/*** 数据对象映射表,用于存储策略执行过程中的中间数据*/private Map<String, Object> dataObjects = new HashMap<>();/*** 设置上下文值* @param key 键名* @param value 值(泛型支持任意类型)* @param <T> 值类型*/public <T> void setValue(String key, T value) {dataObjects.put(key, value);}/*** 获取上下文值* @param key 键名* @param <T> 返回值类型* @return 对应的值,如果不存在则返回null*/public <T> T getValue(String key) {return (T) dataObjects.get(key);}}
}
3.2 AbstractSupport 规则树抽象支持类
AbstractSupport 继承自多线程策略路由器,为具体业务实现提供基础支持。它使用 DefaultStrategyFactory.DynamicContext 作为策略执行的上下文,并提供缺省的多线程执行方法。
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;/*** 抽象支持类* 继承自多线程策略路由器,为具体业务实现提供基础支持* * 功能说明:* 1. 作为业务策略路由的抽象基类,提供多线程策略执行框架* 2. 使用DefaultStrategyFactory.DynamicContext作为策略执行的上下文* 3. 提供缺省的多线程执行方法,子类可根据需要重写* * 泛型参数说明:* - String: 请求参数类型* - DefaultStrategyFactory.DynamicContext: 动态上下文类型,用于策略间数据传递* - String: 返回结果类型*/
public abstract class AbstractSupport extends AbstractMultiThreadStrategyRouter<String, DefaultStrategyFactory.DynamicContext, String> {/*** 多线程执行方法(缺省实现)* 子类可以重写此方法来实现具体的多线程业务逻辑* * @param requestParameter 请求参数* @param dynamicContext 动态上下文,包含策略执行过程中的共享数据* @throws ExecutionException 执行过程中出现的异常* @throws InterruptedException 线程中断异常* @throws TimeoutException 执行超时异常*/@Overrideprotected void multiThread(String requestParameter, DefaultStrategyFactory.DynamicContext dynamicContext) throws ExecutionException, InterruptedException, TimeoutException {// 缺省的空实现,子类需要根据具体业务重写此方法// 默认不执行任何多线程操作,直接由单线程策略路由处理}}
3.3 RootNode 根节点策略处理器
RootNode 是规则决策树的入口节点,负责整个策略链的启动和路由。它接收初始请求,并将请求路由到下一个合适的策略处理器。
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;/*** 根节点策略处理器* 作为规则决策树的入口节点,负责整个策略链的启动和路由** 功能说明:* 1. 作为决策树的起始节点,接收初始请求* 2. 负责将请求路由到下一个合适的策略处理器(SwitchRoot)* 3. 记录根节点的执行日志,便于跟踪和调试** 设计特点:* - 继承AbstractSupport,具备多线程策略路由能力* - 使用@Component注解,作为Spring Bean管理* - 使用@Slf4j注解,提供日志记录能力*/
@Slf4j
@Component
public class RootNode extends AbstractSupport {// 下一级策略处理器(路由开关节点)@Autowiredprivate SwitchRoot switchRoot;/*** 业务处理方法* 实现具体的业务逻辑,这里是启动策略路由** @param requestParameter 请求参数(用户ID)* @param dynamicContext 动态上下文* @return 策略执行结果* @throws Exception 执行过程中可能抛出的异常*/@Overrideprotected String doApply(String requestParameter, DefaultStrategyFactory.DynamicContext dynamicContext) throws Exception {// 记录根节点执行日志log.info("【根节点】规则决策树 userId:{}", requestParameter);// 启动策略路由,将请求传递给下一个处理器return router(requestParameter, dynamicContext);}/*** 策略映射方法* 根据请求参数和上下文返回下一个策略处理器** @param requestParameter 请求参数* @param dynamicContext 动态上下文* @return 下一个策略处理器(SwitchRoot)* @throws Exception 映射过程中可能抛出的异常*/@Overridepublic StrategyHandler<String, DefaultStrategyFactory.DynamicContext, String> get(String requestParameter, DefaultStrategyFactory.DynamicContext dynamicContext) throws Exception {// 直接返回SwitchRoot作为下一个处理器// 这里可以根据业务逻辑实现更复杂的路由选择return switchRoot;}}
3.4 SwitchRoot 开关节点策略处理器
SwitchRoot 是规则决策树中的路由开关,负责将请求转发到具体的业务处理节点。它作为中间路由节点,记录执行日志并传递请求。
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;/*** 开关节点策略处理器* 作为规则决策树中的路由开关,负责将请求转发到具体的业务处理节点** 功能说明:* 1. 作为决策树中的中间路由节点,接收来自根节点的请求* 2. 负责将请求路由到具体的业务处理节点(AccountNode)* 3. 记录开关节点的执行日志,便于跟踪请求流转** 设计特点:* - 继承AbstractSupport,具备多线程策略路由能力* - 使用@Component注解,作为Spring Bean管理* - 使用@Slf4j注解,提供日志记录能力* - 作为纯路由节点,不包含具体业务逻辑*/
@Slf4j
@Component
public class SwitchRoot extends AbstractSupport {// 具体的业务处理节点(账户节点)@Autowiredprivate AccountNode accountNode;/*** 业务处理方法* 实现路由转发逻辑,将请求传递给下一个处理器** @param requestParameter 请求参数(用户ID)* @param dynamicContext 动态上下文* @return 策略执行结果* @throws Exception 执行过程中可能抛出的异常*/@Overrideprotected String doApply(String requestParameter, DefaultStrategyFactory.DynamicContext dynamicContext) throws Exception {// 记录开关节点执行日志log.info("【开关节点】规则决策树 userId:{}", requestParameter);// 继续策略路由,将请求传递给下一个处理器return router(requestParameter, dynamicContext);}/*** 策略映射方法* 返回下一个策略处理器(AccountNode)** @param requestParameter 请求参数* @param dynamicContext 动态上下文* @return 下一个策略处理器(AccountNode)* @throws Exception 映射过程中可能抛出的异常*/@Overridepublic StrategyHandler<String, DefaultStrategyFactory.DynamicContext, String> get(String requestParameter, DefaultStrategyFactory.DynamicContext dynamicContext) throws Exception {// 固定返回AccountNode作为下一个处理器// 这里可以实现基于条件判断的动态路由逻辑return accountNode;}}
3.5 AccountNode 账户节点策略处理器
AccountNode 负责账户相关的业务逻辑处理,包括多线程异步数据加载和条件路由。它根据账户状态和用户级别进行动态路由决策。
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeoutException;/*** 账户节点策略处理器* 负责账户相关的业务逻辑处理,包括多线程异步数据加载和条件路由** 功能说明:* 1. 多线程异步加载账户相关数据(账户状态、授信数据)* 2. 根据账户状态和用户级别进行动态路由决策* 3. 作为业务处理节点,包含具体的业务逻辑** 设计特点:* - 重写multiThread方法,实现多线程异步数据加载* - 根据业务条件动态选择下一个处理器* - 使用线程池执行异步任务,提高性能*/
@Slf4j
@Component
public class AccountNode extends AbstractSupport {// 会员级别1节点处理器@Autowiredprivate MemberLevelNode1 memberLevelNode1;// 会员级别2节点处理器@Autowiredprivate MemberLevelNode2 memberLevelNode2;// 线程池执行器,用于执行异步任务@Resourceprivate ThreadPoolExecutor threadPoolExecutor;/*** 多线程异步数据加载方法* 并行加载账户相关的多个数据源,提高执行效率** @param requestParameter 请求参数* @param dynamicContext 动态上下文* @throws ExecutionException 执行异常* @throws InterruptedException 线程中断异常* @throws TimeoutException 超时异常*/@Overrideprotected void multiThread(String requestParameter, DefaultStrategyFactory.DynamicContext dynamicContext) throws ExecutionException, InterruptedException, TimeoutException {// 异步任务1:查询账户标签状态CompletableFuture<String> accountType01 = CompletableFuture.supplyAsync(() -> {log.info("异步查询账户标签,账户标签;开户|冻结|止付|可用");return new Random().nextBoolean() ? "账户冻结" : "账户可用";}, threadPoolExecutor);// 异步任务2:查询授信数据状态CompletableFuture<String> accountType02 = CompletableFuture.supplyAsync(() -> {log.info("异步查询授信数据,拦截|已授信|已降档");return new Random().nextBoolean() ? "拦截" : "已授信";}, threadPoolExecutor);// 等待所有异步任务完成,并将结果存入上下文CompletableFuture.allOf(accountType01, accountType02).thenRun(() -> {dynamicContext.setValue("accountType01", accountType01.join());dynamicContext.setValue("accountType02", accountType02.join());}).join();}/*** 业务处理方法* 执行账户相关的业务逻辑,并设置用户级别信息** @param requestParameter 请求参数(用户ID)* @param dynamicContext 动态上下文* @return 策略执行结果* @throws Exception 执行过程中可能抛出的异常*/@Overrideprotected String doApply(String requestParameter, DefaultStrategyFactory.DynamicContext dynamicContext) throws Exception {log.info("【账户节点】规则决策树 userId:{}", requestParameter);// 模拟查询用户级别(实际项目中应从数据库或服务获取)int level = new Random().nextInt(2);log.info("模拟查询用户级别 level:{}", level);// 将用户级别信息存入上下文,供后续节点使用dynamicContext.setLevel(level);// 继续策略路由return router(requestParameter, dynamicContext);}/*** 策略映射方法* 根据账户状态和用户级别动态选择下一个处理器** @param requestParameter 请求参数* @param dynamicContext 动态上下文* @return 下一个策略处理器* @throws Exception 映射过程中可能抛出的异常*/@Overridepublic StrategyHandler<String, DefaultStrategyFactory.DynamicContext, String> get(String requestParameter, DefaultStrategyFactory.DynamicContext dynamicContext) throws Exception {// 从上下文中获取异步加载的数据String accountType01 = dynamicContext.getValue("accountType01");String accountType02 = dynamicContext.getValue("accountType02");int level = dynamicContext.getLevel();// 路由决策逻辑:// 1. 如果账户冻结,路由到会员级别1节点(可能是处理异常状态)if ("账户冻结".equals(accountType01)) {return memberLevelNode1;}// 2. 如果授信数据被拦截,路由到会员级别1节点if ("拦截".equals(accountType02)) {return memberLevelNode1;}// 3. 根据用户级别路由到不同的处理节点if (level == 1) {return memberLevelNode1;}// 4. 默认路由到会员级别2节点return memberLevelNode2;}}
3.6 MemberLevelNode1 会员级别1节点策略处理器
MemberLevel1Node 负责处理级别1会员的具体业务逻辑,作为决策树的终端节点之一。它执行级别1会员的特定业务逻辑并返回结果。
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;/*** 会员级别1节点策略处理器* 负责处理级别1会员的具体业务逻辑,作为决策树的终端节点之一** 功能说明:* 1. 执行级别1会员的特定业务逻辑* 2. 作为决策链的终端节点,返回最终处理结果* 3. 记录级别1节点的执行日志,便于跟踪和监控** 设计特点:* - 终端节点设计,不继续路由到其他节点* - 直接返回业务处理结果,结束决策流程* - 使用FastJSON序列化上下文信息,便于结果展示*/
@Slf4j
@Component
public class MemberLevelNode1 extends AbstractSupport {/*** 业务处理方法* 执行级别1会员的具体业务逻辑并返回结果** @param requestParameter 请求参数(用户ID)* @param dynamicContext 动态上下文,包含决策过程中的所有数据* @return 业务处理结果字符串,格式为"level1" + 上下文JSON* @throws Exception 执行过程中可能抛出的异常*/@Overrideprotected String doApply(String requestParameter, DefaultStrategyFactory.DynamicContext dynamicContext) throws Exception {// 记录级别1节点的执行日志log.info("【级别节点-1】规则决策树 userId:{}", requestParameter);// 返回处理结果:级别标识 + 上下文信息的JSON字符串return "level1" + JSON.toJSONString(dynamicContext);}/*** 策略映射方法* 作为终端节点,直接返回默认策略处理器,结束路由流程** @param requestParameter 请求参数* @param dynamicContext 动态上下文* @return 默认策略处理器,实际不会继续执行* @throws Exception 映射过程中可能抛出的异常*/@Overridepublic StrategyHandler<String, DefaultStrategyFactory.DynamicContext, String> get(String requestParameter, DefaultStrategyFactory.DynamicContext dynamicContext) throws Exception {// 返回默认策略处理器,表示不再继续路由// 在实际执行中,router方法会检查到这是默认处理器并结束流程return defaultStrategyHandler;}
}
3.7 MemberLevelNode2 会员级别2节点策略处理器
MemberLevel2Node 负责处理级别2会员的具体业务逻辑,作为决策树的另一个终端节点。它执行级别2会员的特定业务逻辑并返回结果。
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;/*** 会员级别2节点策略处理器* 负责处理级别2会员的具体业务逻辑,作为决策树的另一个终端节点** 功能说明:* 1. 执行级别2会员的特定业务逻辑* 2. 作为决策链的终端节点,返回最终处理结果* 3. 记录级别2节点的执行日志,便于跟踪和监控** 设计特点:* - 终端节点设计,不继续路由到其他节点* - 直接返回业务处理结果,结束决策流程* - 使用FastJSON序列化上下文信息,便于结果展示* - 与MemberLevelNode1结构对称,处理不同级别的会员*/
@Slf4j
@Component
public class MemberLevelNode2 extends AbstractSupport {/*** 业务处理方法* 执行级别2会员的具体业务逻辑并返回结果** @param requestParameter 请求参数(用户ID)* @param dynamicContext 动态上下文,包含决策过程中的所有数据* @return 业务处理结果字符串,格式为"level2" + 上下文JSON* @throws Exception 执行过程中可能抛出的异常*/@Overrideprotected String doApply(String requestParameter, DefaultStrategyFactory.DynamicContext dynamicContext) throws Exception {// 记录级别2节点的执行日志log.info("【级别节点-2】规则决策树 userId:{}", requestParameter);// 返回处理结果:级别标识 + 上下文信息的JSON字符串return "level2" + JSON.toJSONString(dynamicContext);}/*** 策略映射方法* 作为终端节点,直接返回默认策略处理器,结束路由流程** @param requestParameter 请求参数* @param dynamicContext 动态上下文* @return 默认策略处理器,实际不会继续执行* @throws Exception 映射过程中可能抛出的异常*/@Overridepublic StrategyHandler<String, DefaultStrategyFactory.DynamicContext, String> get(String requestParameter, DefaultStrategyFactory.DynamicContext dynamicContext) throws Exception {// 返回默认策略处理器,表示不再继续路由// 在实际执行中,router方法会检查到这是默认处理器并结束流程return defaultStrategyHandler;}}
3.8 Test 规则树测试类
DesignTest 用于测试策略模式决策树的完整执行流程。它获取策略处理器,创建动态上下文,执行策略处理链,并输出最终结果。
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import javax.annotation.Resource;/*** 设计框架测试类* 用于测试策略模式决策树的完整执行流程** 功能说明:* 1. 测试整个规则决策树的执行流程* 2. 验证策略模式框架的正确性和性能* 3. 展示策略模式在实际业务中的应用效果** 测试流程:* 1. 获取策略处理器(根节点)* 2. 创建动态上下文* 3. 执行策略处理链* 4. 输出最终结果*/
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest()
public class Test {// 注入策略工厂,用于获取策略处理器@Resourceprivate DefaultStrategyFactory defaultStrategyFactory;/*** 策略模式决策树测试方法* 测试完整的决策树执行流程** @throws Exception 执行过程中可能抛出的异常*/@Testpublic void test() throws Exception {// 1. 获取策略处理器(从根节点开始)StrategyHandler<String, DefaultStrategyFactory.DynamicContext, String> strategyHandler = defaultStrategyFactory.strategyHandler();// 2. 创建动态上下文对象,用于在策略节点间传递数据DefaultStrategyFactory.DynamicContext dynamicContext = new DefaultStrategyFactory.DynamicContext();// 3. 执行策略处理链,传入用户ID和上下文String result = strategyHandler.apply("yang", dynamicContext);// 4. 输出测试结果log.info("测试结果:{}", result);}}
3.9 测试结果
测试结果显示,规则树模式能够成功执行复杂的业务逻辑,并通过多线程异步加载数据提高性能。测试结果包括各级节点的执行日志和最终处理结果。
INFO RootNode - 【根节点】规则决策树 userId:yang
INFO SwitchRoot - 【开关节点】规则决策树 userId:yang
INFO AccountNode - 异步查询账户标签,账户标签;开户|冻结|止付|可用
INFO AccountNode - 异步查询授信数据,拦截|已授信|已降档
INFO AccountNode - 【账户节点】规则决策树 userId:yang
INFO AccountNode - 模拟查询用户级别 level:1
INFO MemberLevelNode1 - 【级别节点-1】规则决策树 userId:yang
INFO DesignFrameworkTest - 测试结果:level1{"dataObjects":{"accountType02":"已授信","accountType01":"账户可用"},"level":1}
四、总结
规则树模式为处理复杂业务规则提供了优雅而强大的解决方案。通过将业务规则抽象为树形结构,我们实现了业务逻辑与核心代码的解耦,大大提高了系统的灵活性、可维护性和可扩展性。
核心优势
解耦与复用:业务规则与核心逻辑分离,规则可以复用和独立变化
灵活可配置:支持动态调整规则,无需修改代码和重新部署
可视化与可调试:规则树结构清晰,便于理解和调试复杂业务逻辑
性能优化:通过缓存、并行执行等技术提升规则执行效率
监控追踪:完整的执行追踪和监控能力,便于问题排查和性能分析
适用场景
业务规则复杂且频繁变更的系统、需要支持动态配置和热更新的业务场景、对可维护性和可扩展性要求较高的企业级应用、需要可视化展示和调试复杂业务规则的场景
实施建议
从简单的规则开始,逐步构建复杂的规则树、使用注解和反射机制实现规则节点的自动发现和管理、为规则节点添加缓存和监控能力,提升性能和可观测性、建立规则版本管理机制,支持规则的回滚和对比、提供规则可视化工具,降低业务人员的理解成本
规则树模式不仅是技术实现,更是一种架构思维。它帮助我们更好地处理复杂性,构建出更加灵活和健壮的软件系统。在数字化转型的今天,这种能力显得尤为重要。
如果有新的想法或问题,欢迎评论区留言讨论!