营销项目--9. 模板模式串联抽奖规则
通过模板模式,整合责任链、规则树,定义出抽奖的标准过程。以及让子类做具体调用功能实现。将上一节中的规则树结构设计整合到抽奖过程中。这样整个抽奖过程就会包括:责任链进行抽奖前的规则过滤并计算抽奖结果,基于抽奖结果再进行规则树的过滤,最终返回抽奖结果
开发流程
- 增加3个po,组装树的po
- 增加3个po对应的dao操作 视频7分钟
- 定义dao 对应的mybatis mapper,映射到mysql,并集中在
RuleTreeDaoTest
中测试,发现了一个bug,在[[Bug记录]] - 在仓库
StrategyRepository
定义queryRuleTreeVOByTreeId
函数。可以在redis中存下来这样的树型结构(根据数据库中ruleTree,ruleTreeNode,ruleTreeNodeLine)构建 - 重构抽奖流程
因此从上看出来在责任链的过程中。之前的
performRaffle(raffleFactorEntity)
流程是
1. 进行抽奖因子的参数校验,userId, strategyId
是否合法
2. 通过责任链工厂获得责任链defaultChainFactory.openLogicChain(strategyId)
3. 通过责任链进行抽奖 拿到奖品id
4. 根据奖品id查询对应的奖品规则进行过滤。兜底奖励,次数锁,库存处理等 返回最终结果rule_blacklist --> rule_weight ->default
. 不是所有规则都需要走后续的处理,比如如果是黑名单直接返回结果就行了。所以需要改造logic
的返回类型,之前都是Integer logic(String userid, Long strategyId)
直接返回奖品id。现在在责任链工厂DefaultChainFactory
中 新增奖品实体对象StrategyAwardVO
有两个属性awardId LogicModel
- 在AbstractRaffleStrategy中定义
raffleLogicChain
方法和raffleLogicTree
方法。重构实现performRaffle。在子类DefaultRaffleStrategy
中实现上述两个方法
重构前的代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public RaffleAwardEntity performRaffle(RaffleFactorEntity raffleFactorEntity) {
//1. 参数校验
String userId = raffleFactorEntity.getUserId();
Long strategyId = raffleFactorEntity.getStrategyId();
if (strategyId == null || StringUtils.isBlank(userId)){
throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());
}
// 2. 获取抽奖责任链 - 前置规则的责任链处理
ILogicChain logicChain = defaultChainFactory.openLogicChain(strategyId);
//3.通过责任链获得奖品id
Integer awardId = logicChain.logic(userId, strategyId);
//4.拿到奖品id后,查询对应的奖品规则
//抽奖中:awardId 对应的 ruleModel有可能的rule_lock和 rule_luck_award进行次数规则过滤
//抽奖后:扣减完奖品库存后过滤,抽奖中拦截和无库存走兜底奖品
StrategyAwardRuleModelVO strategyAwardRuleModelVO = repository.queryStrategyAwardRuleModelVO(strategyId, awardId);
log.info("拿到strategyawardRuleModel:{}",strategyAwardRuleModelVO.getRuleModels());
//5. 抽奖中 - 规则过滤
//将只有是抽奖中的规则传入doCheckRaffleCenter函数中
RuleActionEntity<RuleActionEntity.RaffleCenterEntity> ruleActionCenterEntity = this.doCheckRaffleCenterLogic(RaffleFactorEntity.builder()
.userId(userId)
.strategyId(strategyId)
.awardId(awardId)
.build(),strategyAwardRuleModelVO.raffleCenterRuleModelList());
if (RuleLogicCheckTypeVO.TAKE_OVER.getCode().equals(ruleActionCenterEntity.getCode())){
log.info("[临时日志]:抽奖中 规则过滤,用户抽奖次数小于ruleValue,走rule_luck_award过滤规则");
return RaffleAwardEntity.builder()
.awardDesc("用户抽奖次数小于ruleValue,走rule_luck_award过滤规则")
.build();
}
return RaffleAwardEntity.builder()
.awardId(awardId)
.build();
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
protected RuleActionEntity<RuleActionEntity.RaffleCenterEntity> doCheckRaffleCenterLogic(RaffleFactorEntity raffleFactorEntity, String... logics) {
//1.检查传入的ruleModel是否为空
if (logics == null || logics.length == 0) return RuleActionEntity.<RuleActionEntity.RaffleCenterEntity>builder()
.code(RuleLogicCheckTypeVO.ALLOW.getCode())
.info(RuleLogicCheckTypeVO.ALLOW.getInfo())
.build();
//2.获取过滤器logicFilterGroup
Map<String, ILogicFilter<RuleActionEntity.RaffleCenterEntity>> logicFilterMap = logicFactory.openLogicFilter();
RuleActionEntity<RuleActionEntity.RaffleCenterEntity> ruleActionEntity = null;
//3. 遍历logics进行规则过滤
for(String ruleModel : logics){
RuleMatterEntity ruleMatterEntity = new RuleMatterEntity();
ruleMatterEntity.setUserId(raffleFactorEntity.getUserId());
ruleMatterEntity.setStrategyId(raffleFactorEntity.getStrategyId());
ruleMatterEntity.setAwardId(raffleFactorEntity.getAwardId());
ruleMatterEntity.setRuleModel(ruleModel);
ILogicFilter<RuleActionEntity.RaffleCenterEntity> logicFilter = logicFilterMap.get(ruleModel);
ruleActionEntity = logicFilter.filter(ruleMatterEntity);
log.info("抽奖中规则过滤 userId: {} ruleModel: {} code: {} info: {}", raffleFactorEntity.getUserId(), ruleModel, ruleActionEntity.getCode(), ruleActionEntity.getInfo());
if (!RuleLogicCheckTypeVO.ALLOW.getCode().equals(ruleActionEntity.getCode())) return ruleActionEntity;
}
return ruleActionEntity;
}
连线 节点 整颗树
1 | 连线Map {rule_from:{ruleTreeLineList}} |
1 | 节点map {rule_key: ruleTreeNode} |
1 | ruleTree |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Priska's blog!