BigMarker-抽奖前置规则过滤

需求

在我们的流程设计中,用户执行抽奖时会判断是否已经超过N积分,如果超过N积分则可以在限定范围内进行抽奖。同时如果用户是黑名单范围的羊毛党用户,则只返回固定的奖品ID

模型

  1. 整个规则来说,分为抽奖前、抽奖中、抽奖后,三个阶段执行。本节我们先来处理抽奖前的规则。
  2. 在工程分包上,需要添加 rule 来处理抽奖规则,在添加 raffle 处理抽奖过程。

前置规则判断根据现有的积分决定能抽到什么,以及黑名单

新增实体

RaffleAwardEntity:抽奖结束后要返回一个奖品直接返回一些key交给后续Award有关的列进行处理

RaffleFactorEntity:抽奖因子(参数)抽奖策略接口的参数

RaffleActionEntity:返回一个对象实体,用于你抽奖前后的操作,如抽奖之前是否有解锁,

分为抽奖前过滤规则,抽奖中过滤规则,抽奖后过滤规则(如抽到了但未解锁,返回随机积分)

定义了一个名为RuleActionEntity的泛型类,其中泛型类型T必须是RuleActionEntity.RaffleEntity的子类。同时,该类内部还定义了四个静态内部类:RaffleEntityRaffleBeforeEntityRaffleCenterEntityRaffleAfterEntity,它们都是RaffleEntity的子类。

这些类用于表示不同的抽奖阶段或状态。,RaffleBeforeEntity表示抽奖开始前的状态,RaffleCenterEntity表示抽奖进行中的状态,而RaffleAfterEntity表示抽奖结束后的状态。

重新回答

||

RuleMatterRntity: 用于过滤和过滤接口配合使用

过滤接口

抽奖策略接口——传入因子放回奖品key

RaffleActionEntity:放回一些要用到的参数如权重值策略id还有用于黑名单的奖品id100

@Getter
@AllArgsConstructor
public enum RuleLogicCheckTypeVO {

    ALLOW("0000", "放行;执行后续的流程,不受规则引擎影响"),
    TAKE_OVER("0001","接管;后续的流程,受规则引擎执行结果影响"),
    ;

    private final String code;
    private final String info;

}

控制如何进行下一步这是一个Java枚举类,名为RuleLogicCheckTypeVO。它有两个枚举值:ALLOW和TAKE_OVER。每个枚举值都有一个对应的code和info属性。这个枚举类用于表示规则引擎的逻辑检查类型

public interface ILogicFilter<T extends RuleActionEntity.RaffleEntity> {

    RuleActionEntity<T> filter(RuleMatterEntity ruleMatterEntity);

}

这里抽奖规则过滤接口 用RuleActionEntity要注意基础应为RuleActionEntity规定了,这样就可以返回一个RuleActionEntity的对象,具体是什么取决于具体场景

建立一个工厂方便规则,以及接口实现  annotation方便注入

完整代码详细理解

package org.example.domain.strategy.model.entity;

import lombok.*;
import org.example.domain.strategy.model.vo.RuleLogicCheckTypeVO;

/**
 * @author xy
 * @description 返回一个对象实体,用于返回之后的操作
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class RuleActionEntity<T extends RuleActionEntity.RaffleEntity> {

    private String code= RuleLogicCheckTypeVO.ALLOW.getCode();
    private String info=RuleLogicCheckTypeVO.ALLOW.getInfo();
    private String ruleModel;
    private T data;
    static public class RaffleEntity{


    }

    @EqualsAndHashCode(callSuper = true)
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    /**抽奖前*/
    static public class RaffleBeforeEntity extends RaffleEntity{
        /**策略id*/
        private Long strategyId;
        /**权重值:用于抽奖可以选择权重*/
        private String ruleWeightValueKey;
        /**奖品ID*/
        private Integer awardId;
    }
    /**抽奖中*/
    static public class RaffleCenterEntity extends RaffleEntity{

    }

    /**抽奖后*/
    static public class RaffleAfterEntity extends RaffleEntity{

    }

}

包含了一些属性和方法。这个类使用了Lombok库来简化代码,提供了@Data、@AllArgsConstructor、@NoArgsConstructor和@Builder注解。这个类还定义了一个内部类RaffleEntity,以及三个继承自RaffleEntity的内部类:RaffleBeforeEntity、RaffleCenterEntity和RaffleAfterEntity。这些内部类分别表示抽奖前、抽奖中和抽奖后的操作。还规定了泛型,还有code和info用来输出到控制台以及后续的筛查

@EqualsAndHashCode(callSuper = true)
//,用于自动生成 equals 和 hashCode 方法。当一个类继承了另一个类时,
// 如果想让子类的 equals 和 hashCode 方法同时考虑父类的属性,就需要在子类上使用这个注解
//将callSuper属性设置为true。这样,在生成的equals和hashCode方法中,会先调用父类的相应方法,然后再考虑子类的字段

/**
 * @author xy
 * @description
 */
@Slf4j
public abstract class AbstractRaffleStrategy implements IRaffleStrategy {

    //策略仓储服务-》domain层像一个大厨,仓储层提供米面油盐
    protected IStrategyRepository repository;
    //策略调度服务-》只负责抽奖处理,通过调用接口的方式,隔离职责,不需要使用方关心或者调用抽奖的初始化
    protected IStrategyDispatch strategyDispatch;


    public AbstractRaffleStrategy(IStrategyRepository repository, IStrategyDispatch strategyDispatch) {
        this.repository = repository;
        this.strategyDispatch = strategyDispatch;
    }

    @Override
    public RaffleAwardEntity performRaffle(RaffleFactorEntity raffleFactorEntity) {

        // 1. 参数校验
        String userId = raffleFactorEntity.getUserId();
        Long strategyId = raffleFactorEntity.getStrategyId();
        if (null == strategyId || StringUtils.isBlank(userId)) {
            throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());
        }

        // 2. 策略查询 得到了 id 模型 即strategy策略表的内容
        StrategyEntity strategy = repository.queryStrategyEntityByStrategyId(strategyId);

        // 3. 抽奖前 - 规则过滤
        RuleActionEntity<RuleActionEntity.RaffleBeforeEntity> ruleActionEntity = this.doCheckRaffleBeforeLogic(RaffleFactorEntity.builder().userId(userId).strategyId(strategyId).build(), strategy.ruleModels());

        if (RuleLogicCheckTypeVO.TAKE_OVER.getCode().equals(ruleActionEntity.getCode())) {
            if (DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode().equals(ruleActionEntity.getRuleModel())) {
                // 黑名单返回固定的奖品ID
                return RaffleAwardEntity.builder()
                        .awardId(ruleActionEntity.getData().getAwardId())
                        .build();
            } else if (DefaultLogicFactory.LogicModel.RULE_WIGHT.getCode().equals(ruleActionEntity.getRuleModel())) {
                // 权重根据返回的信息进行抽奖
                RuleActionEntity.RaffleBeforeEntity raffleBeforeEntity = ruleActionEntity.getData();
                String ruleWeightValueKey = raffleBeforeEntity.getRuleWeightValueKey();
                Integer awardId = strategyDispatch.getRandomAwardId(strategyId, ruleWeightValueKey);
                return RaffleAwardEntity.builder()
                        .awardId(awardId)
                        .build();
            }
        }

        // 4. 默认抽奖流程
        Integer awardId = strategyDispatch.getRandomAwardId(strategyId);

        return RaffleAwardEntity.builder()
                .awardId(awardId)
                .build();
    }

    protected abstract RuleActionEntity<RuleActionEntity.RaffleBeforeEntity> doCheckRaffleBeforeLogic(RaffleFactorEntity build, String ...logics);
}

AbstractRaffleStrategy,实现了IRaffleStrategy接口。它主要用于处理抽奖策略的逻辑。在这个类中,定义了一些成员变量,如repositorystrategyDispatch,分别用于存储策略数据和执行抽奖操作。同时,提供了一个构造函数,用于初始化这两个成员变量。

performRaffle方法是这个类的核心方法,用于执行抽奖操作。它首先对输入参数进行校验,然后查询策略信息,接着根据策略规则进行过滤。如果满足某些条件,可以直接返回奖品ID;否则,按照默认的抽奖流程进行抽奖。最后,返回抽奖结果。

在这个Java代码中,使用protected关键字来修饰成员变量(如repositorystrategyDispatch)和方法(如doCheckRaffleBeforeLogicprotected关键字允许子类和同一个包中的其他类访问这些成员。这意味着,当我们创建一个继承自AbstractRaffleStrategy的子类时,这个子类可以直接访问父类中的protected成员,而无需通过公共接口(即public方法)。

package org.example.domain.strategy.service.raffle;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.example.domain.strategy.model.entity.RaffleFactorEntity;
import org.example.domain.strategy.model.entity.RuleActionEntity;
import org.example.domain.strategy.model.entity.RuleMatterEntity;
import org.example.domain.strategy.model.vo.RuleLogicCheckTypeVO;
import org.example.domain.strategy.repository.IStrategyRepository;
import org.example.domain.strategy.service.amory.IStrategyDispatch;
import org.example.domain.strategy.service.rule.ILogicFilter;
import org.example.domain.strategy.service.rule.factory.DefaultLogicFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author xy
 * @description
 */
@Slf4j
@Service
public class DefaultRaffleStrategy extends AbstractRaffleStrategy{

    @Resource
    private DefaultLogicFactory logicFactory;

    public DefaultRaffleStrategy(IStrategyRepository repository, IStrategyDispatch strategyDispatch) {
        super(repository, strategyDispatch);
    }


    @Override
    protected RuleActionEntity<RuleActionEntity.RaffleBeforeEntity> doCheckRaffleBeforeLogic(RaffleFactorEntity raffleFactorEntity, String... logics) {

        Map<String, ILogicFilter<RuleActionEntity.RaffleBeforeEntity>> logicFilterGroup = logicFactory.openLogicFilter();


        // 黑名单规则优先过滤
        String ruleBackList = Arrays.stream(logics)
                .filter(str -> str.contains(DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode()))
                .findFirst()
                .orElse(null);

        if (StringUtils.isNotBlank(ruleBackList)) {
            ILogicFilter<RuleActionEntity.RaffleBeforeEntity> logicFilter = logicFilterGroup.get(DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode());
            RuleMatterEntity ruleMatterEntity = new RuleMatterEntity();
            ruleMatterEntity.setUserId(raffleFactorEntity.getUserId());
            ruleMatterEntity.setAwardId(ruleMatterEntity.getAwardId());
            ruleMatterEntity.setStrategyId(raffleFactorEntity.getStrategyId());
            ruleMatterEntity.setRuleModel(DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode());
            RuleActionEntity<RuleActionEntity.RaffleBeforeEntity> ruleActionEntity = logicFilter.filter(ruleMatterEntity);
            if (!RuleLogicCheckTypeVO.ALLOW.getCode().equals(ruleActionEntity.getCode())) {
                return ruleActionEntity;
            }
        }

        // 顺序过滤剩余规则
        List<String> ruleList = Arrays.stream(logics)
                .filter(s -> !s.equals(DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode()))
                .collect(Collectors.toList());


        RuleActionEntity<RuleActionEntity.RaffleBeforeEntity> ruleActionEntity = null;
        for (String ruleModel : ruleList) {
            ILogicFilter<RuleActionEntity.RaffleBeforeEntity> logicFilter = logicFilterGroup.get(ruleModel);
            RuleMatterEntity ruleMatterEntity = new RuleMatterEntity();
            ruleMatterEntity.setUserId(raffleFactorEntity.getUserId());
            ruleMatterEntity.setAwardId(ruleMatterEntity.getAwardId());
            ruleMatterEntity.setStrategyId(raffleFactorEntity.getStrategyId());
            ruleMatterEntity.setRuleModel(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;
    }
}

这段代码是一个名为`DefaultRaffleStrategy`的Java类,它继承了`AbstractRaffleStrategy`抽象类。这个类主要用于处理抽奖策略的逻辑。在这个类中,定义了一个名为`doCheckRaffleBeforeLogic`的方法,该方法接收一个`RaffleFactorEntity`对象和一个可变参数`logics`,用于检查抽奖前的逻辑。

方法首先创建一个名为`logicFilterGroup`的映射,用于存储不同类型的逻辑过滤器。然后,它会检查传入的`logics`数组中是否包含黑名单规则(`RULE_BLACKLIST`),如果包含,则使用相应的逻辑过滤器对用户进行过滤。如果过滤结果不是允许(`ALLOW`),则直接返回过滤结果。

接下来,方法会过滤剩余的规则,并依次应用这些规则。对于每个规则,它会从`logicFilterGroup`中获取相应的逻辑过滤器,然后使用该过滤器对用户进行过滤。如果过滤结果不是允许(`ALLOW`),则立即返回过滤结果。

最后,如果所有规则都通过了过滤,方法将返回最后一个规则的过滤结果。

相关推荐

  1. 协同过滤条件

    2024-07-17 00:08:04       34 阅读
  2. pwn基础

    2024-07-17 00:08:04       55 阅读
  3. 知识:字符集

    2024-07-17 00:08:04       47 阅读
  4. Vue 导航

    2024-07-17 00:08:04       41 阅读
  5. HTML基础

    2024-07-17 00:08:04       39 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-17 00:08:04       70 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-17 00:08:04       74 阅读
  3. 在Django里面运行非项目文件

    2024-07-17 00:08:04       62 阅读
  4. Python语言-面向对象

    2024-07-17 00:08:04       72 阅读

热门阅读

  1. 学习编程的第一天

    2024-07-17 00:08:04       19 阅读
  2. .gitignore配置文件不生效的问题

    2024-07-17 00:08:04       18 阅读
  3. 坚持日更的意义何在?

    2024-07-17 00:08:04       19 阅读
  4. Android系统中Launcher应用是被谁启动的

    2024-07-17 00:08:04       21 阅读
  5. 智能家居的四种无线技术

    2024-07-17 00:08:04       24 阅读
  6. 定时任务类:使用@Scheduled注解设计定时任务

    2024-07-17 00:08:04       19 阅读