[1.1 规则树的基本概念](#1.1 规则树的基本概念)
[1.2 规则树的类型与适用场景](#1.2 规则树的类型与适用场景)
[2.1 StrategyHandler 策略处理接口](#2.1 StrategyHandler 策略处理接口)
[2.2 StrategyMapper 策略映射器](#2.2 StrategyMapper 策略映射器)
[2.3 AbstractStrategyRouter 策略路由抽象类](#2.3 AbstractStrategyRouter 策略路由抽象类)
[2.4 AbstractMultiThreadStrategyRouter 异步资源加载策略抽象类](#2.4 AbstractMultiThreadStrategyRouter 异步资源加载策略抽象类)
[3.1 DefaultStrategyFactory 默认策略工厂](#3.1 DefaultStrategyFactory 默认策略工厂)
[3.2 AbstractSupport 规则树抽象支持类](#3.2 AbstractSupport 规则树抽象支持类)
[3.3 RootNode 根节点策略处理器](#3.3 RootNode 根节点策略处理器)
[3.4 SwitchRoot 开关节点策略处理器](#3.4 SwitchRoot 开关节点策略处理器)
[3.5 AccountNode 账户节点策略处理器](#3.5 AccountNode 账户节点策略处理器)
[3.6 MemberLevelNode1 会员级别1节点策略处理器](#3.6 MemberLevelNode1 会员级别1节点策略处理器)
[3.7 MemberLevelNode2 会员级别2节点策略处理器](#3.7 MemberLevelNode2 会员级别2节点策略处理器)
[3.8 Test 规则树测试类](#3.8 Test 规则树测试类)
[3.9 测试结果](#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)。
java
/**
* @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 是一个泛型接口,用于根据请求参数和动态上下文获取待执行的策略处理器。它定义了一个方法,根据传入的参数返回对应的策略处理器。
java
/**
* @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 接口,兼具映射和执行能力。该类还提供了一个默认策略处理器,当没有匹配的策略时使用默认处理。
java
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
@Setter
protected 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 扩展了基础策略路由,支持多线程异步数据加载和业务处理分离。它提供了异步数据加载框架,在执行业务逻辑前预先加载所需资源,从而提高系统性能和响应速度。
java
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
@Setter
protected 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 执行过程中可能抛出的异常
*/
@Override
public 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 是一个策略工厂类,负责创建和管理策略处理器,提供策略模式的统一入口。它维护策略执行的上下文信息,支持数据在不同策略节点间传递。
java
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
@NoArgsConstructor
public 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 作为策略执行的上下文,并提供缺省的多线程执行方法。
java
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 执行超时异常
*/
@Override
protected void multiThread(String requestParameter, DefaultStrategyFactory.DynamicContext dynamicContext) throws ExecutionException, InterruptedException, TimeoutException {
// 缺省的空实现,子类需要根据具体业务重写此方法
// 默认不执行任何多线程操作,直接由单线程策略路由处理
}
}
3.3 RootNode 根节点策略处理器
RootNode 是规则决策树的入口节点,负责整个策略链的启动和路由。它接收初始请求,并将请求路由到下一个合适的策略处理器。
java
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 {
// 下一级策略处理器(路由开关节点)
@Autowired
private SwitchRoot switchRoot;
/**
* 业务处理方法
* 实现具体的业务逻辑,这里是启动策略路由
*
* @param requestParameter 请求参数(用户ID)
* @param dynamicContext 动态上下文
* @return 策略执行结果
* @throws Exception 执行过程中可能抛出的异常
*/
@Override
protected 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 映射过程中可能抛出的异常
*/
@Override
public StrategyHandler<String, DefaultStrategyFactory.DynamicContext, String> get(String requestParameter, DefaultStrategyFactory.DynamicContext dynamicContext) throws Exception {
// 直接返回SwitchRoot作为下一个处理器
// 这里可以根据业务逻辑实现更复杂的路由选择
return switchRoot;
}
}
3.4 SwitchRoot 开关节点策略处理器
SwitchRoot 是规则决策树中的路由开关,负责将请求转发到具体的业务处理节点。它作为中间路由节点,记录执行日志并传递请求。
java
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 {
// 具体的业务处理节点(账户节点)
@Autowired
private AccountNode accountNode;
/**
* 业务处理方法
* 实现路由转发逻辑,将请求传递给下一个处理器
*
* @param requestParameter 请求参数(用户ID)
* @param dynamicContext 动态上下文
* @return 策略执行结果
* @throws Exception 执行过程中可能抛出的异常
*/
@Override
protected 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 映射过程中可能抛出的异常
*/
@Override
public StrategyHandler<String, DefaultStrategyFactory.DynamicContext, String> get(String requestParameter, DefaultStrategyFactory.DynamicContext dynamicContext) throws Exception {
// 固定返回AccountNode作为下一个处理器
// 这里可以实现基于条件判断的动态路由逻辑
return accountNode;
}
}
3.5 AccountNode 账户节点策略处理器
AccountNode 负责账户相关的业务逻辑处理,包括多线程异步数据加载和条件路由。它根据账户状态和用户级别进行动态路由决策。
java
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节点处理器
@Autowired
private MemberLevelNode1 memberLevelNode1;
// 会员级别2节点处理器
@Autowired
private MemberLevelNode2 memberLevelNode2;
// 线程池执行器,用于执行异步任务
@Resource
private ThreadPoolExecutor threadPoolExecutor;
/**
* 多线程异步数据加载方法
* 并行加载账户相关的多个数据源,提高执行效率
*
* @param requestParameter 请求参数
* @param dynamicContext 动态上下文
* @throws ExecutionException 执行异常
* @throws InterruptedException 线程中断异常
* @throws TimeoutException 超时异常
*/
@Override
protected 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 执行过程中可能抛出的异常
*/
@Override
protected 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 映射过程中可能抛出的异常
*/
@Override
public 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会员的特定业务逻辑并返回结果。
java
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 执行过程中可能抛出的异常
*/
@Override
protected 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 映射过程中可能抛出的异常
*/
@Override
public StrategyHandler<String, DefaultStrategyFactory.DynamicContext, String> get(String requestParameter, DefaultStrategyFactory.DynamicContext dynamicContext) throws Exception {
// 返回默认策略处理器,表示不再继续路由
// 在实际执行中,router方法会检查到这是默认处理器并结束流程
return defaultStrategyHandler;
}
}
3.7 MemberLevelNode2 会员级别2节点策略处理器
MemberLevel2Node 负责处理级别2会员的具体业务逻辑,作为决策树的另一个终端节点。它执行级别2会员的特定业务逻辑并返回结果。
java
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 执行过程中可能抛出的异常
*/
@Override
protected 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 映射过程中可能抛出的异常
*/
@Override
public StrategyHandler<String, DefaultStrategyFactory.DynamicContext, String> get(String requestParameter, DefaultStrategyFactory.DynamicContext dynamicContext) throws Exception {
// 返回默认策略处理器,表示不再继续路由
// 在实际执行中,router方法会检查到这是默认处理器并结束流程
return defaultStrategyHandler;
}
}
3.8 Test 规则树测试类
DesignTest 用于测试策略模式决策树的完整执行流程。它获取策略处理器,创建动态上下文,执行策略处理链,并输出最终结果。
java
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 {
// 注入策略工厂,用于获取策略处理器
@Resource
private DefaultStrategyFactory defaultStrategyFactory;
/**
* 策略模式决策树测试方法
* 测试完整的决策树执行流程
*
* @throws Exception 执行过程中可能抛出的异常
*/
@Test
public 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 测试结果
测试结果显示,规则树模式能够成功执行复杂的业务逻辑,并通过多线程异步加载数据提高性能。测试结果包括各级节点的执行日志和最终处理结果。
javascript
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}
四、总结
规则树模式为处理复杂业务规则提供了优雅而强大的解决方案。通过将业务规则抽象为树形结构,我们实现了业务逻辑与核心代码的解耦,大大提高了系统的灵活性、可维护性和可扩展性。
核心优势
解耦与复用:业务规则与核心逻辑分离,规则可以复用和独立变化
灵活可配置:支持动态调整规则,无需修改代码和重新部署
可视化与可调试:规则树结构清晰,便于理解和调试复杂业务逻辑
性能优化:通过缓存、并行执行等技术提升规则执行效率
监控追踪:完整的执行追踪和监控能力,便于问题排查和性能分析
适用场景
业务规则复杂且频繁变更的系统、需要支持动态配置和热更新的业务场景、对可维护性和可扩展性要求较高的企业级应用、需要可视化展示和调试复杂业务规则的场景
实施建议
从简单的规则开始,逐步构建复杂的规则树、使用注解和反射机制实现规则节点的自动发现和管理、为规则节点添加缓存和监控能力,提升性能和可观测性、建立规则版本管理机制,支持规则的回滚和对比、提供规则可视化工具,降低业务人员的理解成本
规则树模式不仅是技术实现,更是一种架构思维。它帮助我们更好地处理复杂性,构建出更加灵活和健壮的软件系统。在数字化转型的今天,这种能力显得尤为重要。
如果有新的想法或问题,欢迎评论区留言讨论!