抽奖前的规则过滤是一条链路执行,规则之间也是互斥行为,链路中的节点有一个成功就直接返回。然而在抽奖中后阶段,单独的责任链模式无法满足,因为有分叉的条件,也不是达成某一个规则就直接返回,因此使用组合模式的决策树模型。
![[Pasted image 20241016140744.png]]![[Pasted image 20241016140749.png]]

开发流程

  1. 创建vo。RuleLimitTypeVO,RuleTreeNodeLineVO,RuleTreeNodeVO,RuleTreeVO

    • RuleTreeVO 决策树的树根信息,标记出最开始从哪个节点执行「treeRootRuleNode」。
    • RuleTreeNodeVO 决策树的节点,这些节点可以组合出任意需要的规则树。
    • RuleTreeNodeLineVO 决策树节点连线,用于标识出怎么从一个节点到下一个节点。
  2. 在rule下新增tree package。

  3. 在tree下定义ILogicTreeNode 接口,定义一个logic方法,入参是userId, strategyId, awardId. 出参是DefaultTreeFactory.TreeActionEntity

  4. 在tree下新增impl. 首先开发RuleLockLogicTreeNode次数锁节点。(这个是从数据库判断用户抽奖的次数来判断是否给奖品)

  5. 在impl新增RuleLuckAwardLogicTreeNode. 即兜底奖励节点。当次数锁校验失败,即用户抽奖次数小于数据库中定义的该奖品的最小抽奖解锁次数。以及库存不足时,都会走该节点。这也体现了和责任链的不同,多个分支

  6. 在impl新增RuleStockLogicTreeNode 库存节点

  7. 使用工厂组合这些节点为二叉树/多叉树。在tree下新增factory,新增规则树工厂DefaultTreeFactory, 在工厂下装配Map<String, ILogicTreeNode> logicTreeNodeGroup,但是openLogicTree的具体实现在引擎中实现return new DecisionTreeEngine(logicTreeNodeGroup, ruleTreeVO)。
    7.1 并且在工厂里加两个实体对象TreeActionEntityStrategyAwardData

  8. 在factory新增加引擎:1. 可以让使得工厂类更加专注于创建对象和组织对象之间的关系,而不涉及具体的业务逻辑;如果处理逻辑需要根据不同的情况而变化,那么可以通过创建不同引擎来实现,而不需要修改工厂的代码。一个引擎接口IDecisionTreeEngine
    引擎部分就是咱们前面提到的,责任链有自己自身的链路执行顺序,而这样的二叉调用关系,则需要自己实现

四个VO

RuleLimitTypeVO
枚举类用于定义规则树中的条件操作符。代表了决策树节点连线之间的条件,根据操作符判断是否可以从一个节点跳转到下一个节点
RuleTreeNodeLineVO 规则树节点连线
表示规则树一个节点到另外一个节点之间的连接关系。
并通过RuleLimitTypeVORuleLogicCheckTypeVO 限定从from节点到to节点的条件

作用: 如何从当前节点向下一个节点跳转,连接每个节点的决策路径

RuleTreeNodeVO 规则树节点
每个节点是规则树的基本组成单元。表示一个具体的规则节点,以及该节点的可能跳转路径。每个节点可以有多个连线,定义了该节点可以跳转的下一个节点。

RuleTreeVO 规则树
表示一颗完整的规则树,决策树的根节点结构,包含整个树的元信息以及所有的节点。按规则树节点间的连线依次执行规则,逐步做出决策。

ILogicTreeNode接口

  • 功能:定义了规则树节点的行为,每个规则树节点需要实现logic方法,执行特定的逻辑业务

RuleLockLogicTreeNode 次数锁节点

  • 功能:实现了次数锁节点的逻辑。当用户抽奖次数足够时,节点返回 ALLOW,允许继续流程

RuleLuckAwardLogicNode 兜底奖励节点

  • 功能:实现兜底奖励的逻辑。当用户的抽奖不满足条件或奖品库存不足时,返回一个兜底奖励。

RuleStockLogicTreeNode 库存节点

功能:实现了库存校验的逻辑。如果库存不足,则返回 TAKE_OVER,表示流程被拦截,不能继续。

DefaultTreeFactory 规则树工厂

  • 负责将ILogicTreeNode组合成完整的决策树,并生成相应的引擎对象
  • 通过openLogicTree方法,生成DecisionTreeEngine引擎,后续用于处理规则树的节点执行

DecisionTreeEngine

decisionLogic方法

  • matterValue 是规则执行结果(如ALLOW/TAKE_OVER)
  • nodeLine: 当前连线的限制条件,从当前节点到下一个节点的逻辑
  • 条件匹配: 检查 matterValue 是否满足连线的限制条件。当前只实现了 EQUAL(等于)条件,未来可以扩展为 GT(大于)、LT(小于)等复杂条件。
  • 返回值: 如果满足条件,则返回 true,否则返回 false

nextNode方法

1
2
/matterValue: 规则执行后的返回值,作为判断下一步的依据  
/treeNodeLineVOList: 当前节点的连线列表,决定了如何从当前节点移动到下一个节点
  • 检查连线列表: 如果当前节点没有连线(即 treeNodeLineVOList 为空),返回 null,表示决策结束。
  • 遍历连线: 遍历当前节点的所有连线,调用 decisionLogic 检查是否满足条件。
  • 返回下一节点: 如果某条连线的条件满足,则返回 ruleNodeTo,表示下一个节点。
  • 异常处理: 如果没有找到符合条件的连线,抛出异常。

核心代码 : DecisionTreeEngine.process

  1. 获取树的根节点,map
  2. 开始从树的根节点开始遍历,拿到每个节点对应的logic关系,把入参放进去拿到的结果就可以通过二叉树走下去,二叉树的逻辑是提前设定好的