链式多分支规则树模型结构
链式多分支规则树模型结构,这是一种链式的多分支规则树模型结构,由功能节点自行决定后续流程的执行链路。它比设计比责任链的扩展性更好,自由度也更高。
- 首先,定义抽象的通用的规则树模型结构。涵盖:通过泛型的设计允许使用方可以自定义出入参和动态上下文,让抽象模版模型具有通用性。
- StrategyMapper - 策略映射器
- StrategyHandler - 策略处理器
- AbstractStrategyRouter<T,D,R> - 策略路由抽象类 T:入参 D:动态上下文参数 R:出参
- 之后,由使用方自定义出工厂,功能抽象类和一个个的流程流转的节点,这些节点可以自由组装进行流转,相比较责任链的话它的实现方式更具有灵活性。
代码实现
模型设计
StrategyHandler 策略受理器
策略节点的具体处
public interface StrategyHandler<T, D, R> {
StrategyHandler DEFAULT_NONE_NODE = (T, D) -> null;
/**
* 策略节点处理
* @param requestParameter 请求参数
* @param dynamicContext 动态上下文
* @return R
* @throws Exception 异常
*/
R apply(T requestParameter, D dynamicContext) throws Exception;
}
StrategyMapper 策略映射器
用于获取每一个要执行的节点, 相当于一个流程走完进入到下一个流程的过程
public interface StrategyMapper<T, D, R> {
/**
* 获取待执行的策略处理器
* @param requestParameter 入参
* @param dynamicContext 动态上下文
* @return 策略处理器
* @throws Exception 异常
*/
StrategyHandler<T, D, R> get(T requestParameter, D dynamicContext) throws Exception;
}
AbstractStrategyRouterMapper 策略路由器
通过调用策略映射器的get方法,控制节点流程的走向
@Setter
@Getter
public abstract class AbstractStrategyRouterMapper<T, D, R> implements StrategyMapper<T, D, R>,
StrategyHandler<T, D, R> {
protected StrategyHandler<T, D, R> defaultHandler = StrategyHandler.DEFAULT_NONE_NODE;
public R router(T requestParameter, D dynamicContext) throws Exception {
StrategyHandler<T, D, R> handler = get(requestParameter, dynamicContext);
if (null != handler) {
return handler.apply(requestParameter, dynamicContext);
}
return defaultHandler.apply(requestParameter, dynamicContext);
}
}
模拟业务流程
GroupBuyReq 入参
@Data
@Builder
public class GroupBuyReq {
/**
* 用户id
*/
private Long userId;
/**
* 商品id
*/
private Long goodsId;
}
GroupBuyResp 出参
@Data
public class GroupBuyResp {
/**
* 商品id
*/
private Long goodsId;
/**
* 商品名称
*/
private String goodsName;
/**
* 用户id
*/
private Long userId;
/**
* 原价
*/
private BigDecimal originalPrice;
/**
* 优惠价
*/
private BigDecimal discountPrice;
/**
* 团购开始时间
*/
private LocalDateTime startTime;
/**
* 团购结束时间
*/
private LocalDateTime endTime;
/**
* 是否可见
*/
private Boolean isVisible;
/**
* 是否可以参与
*/
private Boolean isEnable;
}
AbstractGroupBuyRouterSupport 路由增强类
public abstract class AbstractGroupBuyRouterSupport<GroupBuyReq, DynamicContextParam, GroupBuyResp>
extends AbstractStrategyRouterMapper<GroupBuyReq, DynamicContextParam, GroupBuyResp> {
}
DefaultActivityStrategyFactory 默认策略工厂
DynamicContextParam
动态上下文参数
@Component
public class DefaultActivityStrategyFactory {
@Data
public static class DynamicContextParam {
private Integer userId;
private Integer level;
}
@Autowired
private RootNode rootNode;
public GroupBuyResp run(GroupBuyReq req) {
return rootNode.apply(req, new DynamicContextParam());
}
}
各类流程Node节点
@Component
public class RootNode extends AbstractGroupBuyRouterSupport<GroupBuyReq, DefaultActivityStrategyFactory.DynamicContextParam, GroupBuyResp> {
private static final Logger log = LoggerFactory.getLogger(RootNode.class);
@Autowired
private AccountNode accountNode;
@Override
public GroupBuyResp apply(GroupBuyReq req, DefaultActivityStrategyFactory.DynamicContextParam dynamicContext) {
log.info("root node 节点开始 执行..");
return router(req, dynamicContext);
}
@Override
public StrategyHandler<GroupBuyReq, DefaultActivityStrategyFactory.DynamicContextParam, GroupBuyResp> get(GroupBuyReq req, DefaultActivityStrategyFactory.DynamicContextParam dynamicContext) {
return accountNode;
}
}
@Component
public class AccountNode extends AbstractGroupBuyRouterSupport<GroupBuyReq, DefaultActivityStrategyFactory.DynamicContextParam, GroupBuyResp> {
private static final Logger log = LoggerFactory.getLogger(RootNode.class);
@Autowired
private MemberLevel0Node memberLevel0Node;
@Autowired
private MemberLevel1Node memberLevel1Node;
@Autowired
private MemberLevel3Node memberLevel3Node;
@Override
public GroupBuyResp apply(GroupBuyReq req, DefaultActivityStrategyFactory.DynamicContextParam dynamicContext) {
log.info("【账户决策节点】");
// 模拟用户等级查询
int level = RandomUtil.randomInt(3);
log.info("模拟查询用户级别 level:{}", level);
// 上下文参数中填充线程参数
dynamicContext.setLevel(level);
return router(req, dynamicContext);
}
@Override
public StrategyHandler<GroupBuyReq, DefaultActivityStrategyFactory.DynamicContextParam, GroupBuyResp> get(GroupBuyReq req, DefaultActivityStrategyFactory.DynamicContextParam dynamicContext) {
if (dynamicContext.getLevel() == 0) {
return memberLevel0Node;
} else if (dynamicContext.getLevel() == 1) {
return memberLevel1Node;
} else if (dynamicContext.getLevel() == 2) {
return memberLevel3Node;
}
return null;
}
}
@Component
public class MemberLevel0Node extends AbstractGroupBuyRouterSupport<GroupBuyReq, DefaultActivityStrategyFactory.DynamicContextParam, GroupBuyResp> {
private static final Logger log = LoggerFactory.getLogger(MemberLevel0Node.class);
@Override
public GroupBuyResp apply(GroupBuyReq req, DefaultActivityStrategyFactory.DynamicContextParam dynamicContext) {
log.info("用户等级 = 0");
return null;
}
@Override
public StrategyHandler<GroupBuyReq, DefaultActivityStrategyFactory.DynamicContextParam, GroupBuyResp> get(GroupBuyReq req, DefaultActivityStrategyFactory.DynamicContextParam dynamicContext) {
return null;
}
}
@Component
public class MemberLevel1Node extends AbstractGroupBuyRouterSupport<GroupBuyReq, DefaultActivityStrategyFactory.DynamicContextParam, GroupBuyResp> {
private static final Logger log = LoggerFactory.getLogger(MemberLevel1Node.class);
@Override
public GroupBuyResp apply(GroupBuyReq req, DefaultActivityStrategyFactory.DynamicContextParam dynamicContext) {
log.info("用户等级 = 1");
return null;
}
@Override
public StrategyHandler<GroupBuyReq, DefaultActivityStrategyFactory.DynamicContextParam, GroupBuyResp> get(GroupBuyReq req, DefaultActivityStrategyFactory.DynamicContextParam dynamicContext) {
return null;
}
}
@Component
public class MemberLevel3Node extends AbstractGroupBuyRouterSupport<GroupBuyReq, DefaultActivityStrategyFactory.DynamicContextParam, GroupBuyResp> {
private static final Logger log = LoggerFactory.getLogger(MemberLevel3Node.class);
@Override
public GroupBuyResp apply(GroupBuyReq req, DefaultActivityStrategyFactory.DynamicContextParam dynamicContext) {
log.info("用户等级 = 3");
return null;
}
@Override
public StrategyHandler<GroupBuyReq, DefaultActivityStrategyFactory.DynamicContextParam, GroupBuyResp> get(GroupBuyReq req, DefaultActivityStrategyFactory.DynamicContextParam dynamicContext) {
return null;
}
}
链式多分支规则树模型Pro
支持多线程任务处理的路由映射器
模型设计
StrategyHandler 策略受理器
public interface StrategyHandler<T, D, R> {
StrategyHandler DEFAULT_NONE_NODE = (T, D) -> null;
/**
* 策略节点处理
* @param requestParameter 请求参数
* @param dynamicContext 动态上下文
* @return R
* @throws Exception 异常
*/
R apply(T requestParameter, D dynamicContext) throws Exception;
}
StrategyMapper 策略映射器
public interface StrategyMapper<T, D, R> {
/**
* 获取待执行的策略处理器
* @param requestParameter 入参
* @param dynamicContext 动态上下文
* @return 策略处理器
* @throws Exception 异常
*/
StrategyHandler<T, D, R> get(T requestParameter, D dynamicContext) throws Exception;
}
AbstractStrategyRouterMapper 策略路由器
public abstract class AbstractStrategyRouterMapper<T, D, R> implements StrategyMapper<T, D, R>,
StrategyHandler<T, D, R> {
}
AbstractMultiThreadStrategyRouter 支持多线程任务策略路由器
@Setter
@Getter
public abstract class AbstractMultiThreadStrategyRouter<T, D, R> extends AbstractStrategyRouterMapper<T, D, R> {
protected StrategyHandler<T, D, R> defaultHandler = StrategyHandler.DEFAULT_NONE_NODE;
public R router(T requestParameter, D dynamicContext) throws Exception {
StrategyHandler<T, D, R> handler = get(requestParameter, dynamicContext);
if (null != handler) {
return handler.apply(requestParameter, dynamicContext);
}
return defaultHandler.apply(requestParameter, dynamicContext);
}
@Override
public R apply(T requestParameter, D dynamicContext) throws Exception {
// 异步加载数据
multiThread(requestParameter, dynamicContext);
// 业务逻辑处理
return doApply(requestParameter, dynamicContext);
}
/**
* 多线程数据处理
*
* @param requestParameter 请求参数
* @param dynamicContext 动态上下文
* @throws Exception 异常
*/
protected abstract void multiThread(T requestParameter, D dynamicContext) throws Exception;
/**
* 执行
*
* @param requestParameter 请求参数
* @param dynamicContext 动态上下文
* @return R
* @throws Exception 异常
*/
protected abstract R doApply(T requestParameter, D dynamicContext) throws Exception;
}
模拟业务流程
出参,响应参数
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserGroupBuyTrialReq {
/**
* 用户id
*/
private Long userId;
/**
* 商品id
*/
private Long goodsId;
}
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserGroupBuyTrialResp {
/**
* 用户id
*/
private Long userId;
/**
* 商品id
*/
private Long goodsId;
/**
* 商品名称
*/
private String goodsName;
/**
* 商品原价
*/
private BigDecimal originalPrice;
/**
* 商品优惠价
*/
private BigDecimal discountPrice;
/**
* 拼团开始时间
*/
private LocalDateTime startTime;
/**
* 拼团结束时间
*/
private LocalDateTime endTime;
/**
* 拼团人数
*/
private Integer targetPeople;
/**
* 是否可拼团
*/
private Boolean isEnable;
/**
* 是否可见
*/
private Boolean isVisibility;
}
AbstractGroupBuyStrategyRouterSupport 抽象策略路由支持
public abstract class AbstractGroupBuyStrategyRouterSupport
extends AbstractMultiThreadStrategyRouter<UserGroupBuyTrialReq,
DefaultGroupBuyTrialFactory.DynamicContext, UserGroupBuyTrialResp> {
@Override
protected void multiThread(UserGroupBuyTrialReq requestParameter, DefaultGroupBuyTrialFactory.DynamicContext dynamicContext) throws Exception {
// 缺省实现,如果要实现多线程,请重写此方法
}
}
DefaultGroupBuyTrialFactory 默认工厂
@Component
public class DefaultGroupBuyTrialFactory {
@Resource
private RootNode rootNode;
/**
* 动态上下文
*/
@Data
public static class DynamicContext {
}
/**
* 获取试算结果
* @param requestParameter 请求参数
* @return UserGroupBuyTrialResp
* @throws Exception 异常
*/
public UserGroupBuyTrialResp apply(UserGroupBuyTrialReq requestParameter) throws Exception {
return rootNode.apply(requestParameter, new DynamicContext());
}
}
各类流程Node节点
@Slf4j
@Component
public class RootNode extends AbstractGroupBuyStrategyRouterSupport {
@Resource
private SwitchNode switchNode;
@Override
protected UserGroupBuyTrialResp doApply(UserGroupBuyTrialReq requestParameter, DefaultGroupBuyTrialFactory.DynamicContext dynamicContext) throws Exception {
log.info("Root Node 触发...");
if (!ObjUtil.isAllNotEmpty(requestParameter.getUserId(), requestParameter.getGoodsId())) {
throw new BusinessException(ResponseCodeEnum.INVALID_PARAM);
}
return router(requestParameter, dynamicContext);
}
@Override
public StrategyHandler<UserGroupBuyTrialReq, DefaultGroupBuyTrialFactory.DynamicContext, UserGroupBuyTrialResp> get(UserGroupBuyTrialReq requestParameter, DefaultGroupBuyTrialFactory.DynamicContext dynamicContext) throws Exception {
return switchNode;
}
}
@Slf4j
@Component
public class SwitchNode extends AbstractGroupBuyStrategyRouterSupport {
@Resource
private MarketNode marketNode;
@Override
protected UserGroupBuyTrialResp doApply(UserGroupBuyTrialReq requestParameter, DefaultGroupBuyTrialFactory.DynamicContext dynamicContext) throws Exception {
log.info("Switch Node 触发...");
return router(requestParameter, dynamicContext);
}
@Override
public StrategyHandler<UserGroupBuyTrialReq, DefaultGroupBuyTrialFactory.DynamicContext, UserGroupBuyTrialResp> get
(UserGroupBuyTrialReq requestParameter, DefaultGroupBuyTrialFactory.DynamicContext dynamicContext) throws Exception {
return marketNode;
}
}
@Slf4j
@Component
public class MarketNode extends AbstractGroupBuyStrategyRouterSupport {
@Resource
private EndNode endNode;
@Override
protected void multiThread(UserGroupBuyTrialReq requestParameter, DefaultGroupBuyTrialFactory.DynamicContext dynamicContext) throws Exception {
// 试算所需要db数据异步查询
}
@Override
protected UserGroupBuyTrialResp doApply(UserGroupBuyTrialReq requestParameter, DefaultGroupBuyTrialFactory.DynamicContext dynamicContext) throws Exception {
log.info("Market Node 触发...");
return router(requestParameter, dynamicContext);
}
@Override
public StrategyHandler<UserGroupBuyTrialReq, DefaultGroupBuyTrialFactory.DynamicContext, UserGroupBuyTrialResp> get
(UserGroupBuyTrialReq requestParameter, DefaultGroupBuyTrialFactory.DynamicContext dynamicContext) throws Exception {
return endNode;
}
}
@Slf4j
@Component
public class EndNode extends AbstractGroupBuyStrategyRouterSupport {
@Override
protected UserGroupBuyTrialResp doApply(UserGroupBuyTrialReq requestParameter, DefaultGroupBuyTrialFactory.DynamicContext dynamicContext) throws Exception {
log.info("End Node 触发..");
return UserGroupBuyTrialResp.builder()
.goodsId(requestParameter.getGoodsId())
.goodsName("测试商品")
.userId(requestParameter.getUserId())
.discountPrice(BigDecimal.ONE)
.originalPrice(BigDecimal.TEN)
.endTime(LocalDateTime.now())
.startTime(LocalDateTime.now())
.targetPeople(10)
.isEnable(true)
.isVisibility(true)
.build();
}
@Override
public StrategyHandler<UserGroupBuyTrialReq, DefaultGroupBuyTrialFactory.DynamicContext, UserGroupBuyTrialResp> get
(UserGroupBuyTrialReq requestParameter, DefaultGroupBuyTrialFactory.DynamicContext dynamicContext) throws Exception {
return null;
}
}
参考:https://bugstack.cn/md/develop/design-pattern/2024-08-25-chain-tree.html