Loterty抽奖项目【责任链处理抽奖前规则02】

开篇介绍:将按照渐进的顺序逐步编写一个完整的抽奖项目。

责任链模式

通过责任链模式我们可以轻松的实现链式自动前置规则过滤。
例如在抽奖之前我需要先执行黑名单的过滤,黑名单过滤之后还需要执行抽奖权重规则的校验,都放行之后才去继续执行我随机抽奖的步骤,那么黑名单,权重就可以按照链的方式配置好来进行测试。

责任链类结构

ILogicChain接口

这个接口定义了最基本的责任链需要包含的功能;

public interface ILogicChain {
	// 执行链中逻辑判断的功能
    DefaultChainFactory.StrategyAwardVO logic(String userId, Long strategyId);
	// 为当前链添加下一个链
    ILogicChain appendNext(ILogicChain next);
	// 获得下一个链
    ILogicChain next();
}
BlackListLogicChain 黑名单

通过实现上面的抽象类 这个抽象类中实现了上面的接口 变为责任链中的一环

为什么这里要多一层抽象类包装呢?可以看到我们的ILogicChain中只有logic是每个链独立的其他方法都可以共有因此可以用抽象类包装一层把把公共的方法封装好

public abstract class AbstractLogicChain implements ILogicChain {
    private ILogicChain next;
    @Override
    public ILogicChain appendNext(ILogicChain next) {
        this.next = next;
        return next;
    }
    @Override
    public ILogicChain next() {
        return next;
    }
    protected abstract String ruleModel();
}
@Slf4j
@Component("rule_blacklist")
public class BlackListLogicChain extends AbstractLogicChain {

    @Resource
    private IStrategyRepository repository;
	// 校验的逻辑
    @Override
    public DefaultChainFactory.StrategyAwardVO logic(String userId, Long strategyId) {
        String ruleValue = repository.queryStrategyRuleValue(strategyId, null, ruleModel());

        String[] splitRuleValue = ruleValue.split(Constants.COLON);
        // 拿到奖品id
        Integer awardId = Integer.parseInt(splitRuleValue[0]);
        // 拿到黑名单的用户id
        String[] userBlackIds = splitRuleValue[1].split(Constants.SPLIT);
        for (String userBlackId : userBlackIds) {
            if (userId.equals(userBlackId)) {
                log.info("抽奖责任链-黑名单接管");
                return DefaultChainFactory.StrategyAwardVO.builder()
                        .awardId(awardId)
                        .logicModel(ruleModel())
                        .build();
            }
        }
        log.info("抽奖责任链-黑名单放行");
        return next().logic(userId,strategyId);
    }

    @Override
    protected String ruleModel() {
        return "rule_blacklist";
    }
}
RuleWeightLogicChain 权重规则的责任链
@Slf4j
@Component("rule_weight")
public class RuleWeightLogicChain extends AbstractLogicChain {

    @Resource
    private IStrategyRepository repository;

    @Resource
    private IStrategyDispatch strategyDispatch;

    private Long userScore = 5500L;

    @Override
    public DefaultChainFactory.StrategyAwardVO logic(String userId, Long strategyId) {
        String ruleValue = repository.queryStrategyRuleValue(strategyId,null,ruleModel());
        Map<Long, String> analyticalValue = getAnalyticalValue(ruleValue);
        if(null == analyticalValue || analyticalValue.isEmpty()){
            return null;
        }
        // 转换keys 和 排序
        List<Long> analyticalSortedKeys = new ArrayList<>(analyticalValue.keySet());
        Collections.sort(analyticalSortedKeys);

        Long nextValue = analyticalSortedKeys.stream()
                .filter(key -> userScore >= key)
                .findFirst()
                .orElse(null);
        if(null != nextValue){
            Integer awardId = strategyDispatch.getRandomAwardId(strategyId, analyticalValue.get(nextValue));
            log.info("抽奖责任链-权重接管");
            return DefaultChainFactory.StrategyAwardVO.builder()
                    .awardId(awardId)
                    .logicModel(ruleModel())
                    .build();
        }
        // 放行走下一条规则.
        return next().logic(userId,strategyId);
    }

    private Map<Long,String> getAnalyticalValue(String ruleValue){
        String[] ruleValueGroups = ruleValue.split(Constants.SPACE);
        Map<Long,String> ruleValueMap = new HashMap<>();

        for (String ruleValueGroup : ruleValueGroups) {
            if(ruleValueGroup == null || ruleValueGroup.isEmpty()) return ruleValueMap;

            String[] parts = ruleValueGroup.split(Constants.COLON);
            if(parts.length != 2){
                throw new IllegalArgumentException("rule_weight invalid input" + ruleValueGroup);
            }
            // 存入积分值以及对应的规则 4000: 4000:101,102,103
            ruleValueMap.put(Long.parseLong(parts[0]),ruleValueGroup);
        }
        return ruleValueMap;
    }

    @Override
    protected String ruleModel() {
        return "rule_weight";
    }
}
默认规则 default
@Slf4j
@Component("default")
public class DefaultLogicChain extends AbstractLogicChain {

    @Resource
    protected IStrategyDispatch strategyDispatch;

    @Override
    public DefaultChainFactory.StrategyAwardVO logic(String userId, Long strategyId) {
        // 抽奖返回.
        Integer awardId = strategyDispatch.getRandomAwardId(strategyId);
        log.info("抽奖责任链 默认处理 awardId: {}",awardId);
        return DefaultChainFactory.StrategyAwardVO.builder()
                .awardId(awardId)
                .logicModel(ruleModel())
                .build();
    }
    
    @Override
    protected String ruleModel() {
        return "rule_default";
    }
}

默认规则也是抽奖前置责任链过滤的最后一环如果能走到这里证明前面两个均放行,执行抽奖的流程返回一个抽到的奖品id。

DefaultChainFactory 责任链工厂

为什么这里需要工厂呢,有了责任链也就是继承了ILogicChain的3个实现类我们可以通过工厂的方式将他们给串联起来,同时可以将工厂用@Service,在构造方法参数里通过Map的形式自动注入全部的责任链模块方便操作

private final Map<String, ILogicChain> logicChainGroup;

public DefaultChainFactory(Map<String, ILogicChain> logicChainGroup, IStrategyRepository repository) {
        this.logicChainGroup = logicChainGroup;
        this.repository = repository;
}
openLogicChain方法
public ILogicChain openLogicChain(Long strategyId){
	StrategyEntity strategy = repository.queryStrategyEntityByStrategyId(strategyId);
	// 10002L 对应 ruleModels: rule_blacklist,rule_weight
	String[] ruleModels = strategy.ruleModels();
	if(null == ruleModels || 0 == ruleModels.length) return logicChainGroup.get("default");
	// 这里因为logicChainGroup已经将实现了接口的方法全部注入了因此可以直接使用。
	ILogicChain chain = logicChainGroup.get(ruleModels[0]);
	ILogicChain current = chain;
	// 添加责任链
	for(int i=1;i<ruleModels.length;i++){
	    ILogicChain nextChain = logicChainGroup.get(ruleModels[i]);
	    current = current.appendNext(nextChain);
	}
	// 添加默认值 也就是链尾
	current.appendNext(logicChainGroup.get("default"));
	return chain;
}
StrategyAwardVO 工厂里的静态内部类
@Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public static class StrategyAwardVO {
        /** 抽奖奖品ID - 内部流转使用 */
        private Integer awardId;
        /**  */
        private String logicModel;
    }

在每个链进行logic时最后会返回一个StrategyAwardVO这个工厂类中封装的奖品对象,
通过对象的字段来判断这个类是被接管了还是放行走的default逻辑。

具体使用

@Override
public DefaultChainFactory.StrategyAwardVO raffleLogicChain(String userId, Long strategyId) {
    ILogicChain chain = chainFactory.openLogicChain(strategyId);
    DefaultChainFactory.StrategyAwardVO strategyAwardVO = chain.logic(userId, strategyId);
    return strategyAwardVO;
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值