当前位置: 首页 > article >正文

链式多分支规则树模型结构

链式多分支规则树模型结构,这是一种链式的多分支规则树模型结构,由功能节点自行决定后续流程的执行链路。它比设计比责任链的扩展性更好,自由度也更高。

  • 首先,定义抽象的通用的规则树模型结构。涵盖:通过泛型的设计允许使用方可以自定义出入参和动态上下文,让抽象模版模型具有通用性。
    • 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


http://www.kler.cn/a/579609.html

相关文章:

  • robotjs获取鼠标位置
  • c++介绍锁四
  • 快速排序(二叉树的前序递归遍历思想)
  • 【three.js】动画系统完全指南 - 从事件循环到工业级动画架构
  • MobileBERT: 一种适用于资源有限设备的紧凑型任务无关BERT
  • 关于C/C++语言的初学者在哪刷题,怎么刷题
  • 软件系统压力测试方案,压力测试报告模版(Word原件)
  • OSPF-单区域的配置
  • 反射是什么?
  • 数学建模-1:对变化建模
  • Python正则表达式完全指南:从入门到精通
  • 【Linux网络(一)】初始网络
  • Linux:多线程(单例模式,其他常见的锁,读者写者问题)
  • ESP8266UDP透传
  • 华为Mate 60 Pro+ 等机型适配支持运营商北斗卫星短信功能
  • C++:vector容器(下篇)
  • Milvus的匹配语法
  • 二维码识别OCR接口:开启高效信息提取的新篇章
  • RK Android14 在计算器内输入特定字符跳转到其他应用
  • 文件上传漏洞测试