美文网首页
简单疲劳度模型设计(JAVA实现)

简单疲劳度模型设计(JAVA实现)

作者: 灰气球 | 来源:发表于2023-08-12 19:40 被阅读0次

    应用场景

    疲劳度模型在很多场景下都是必不可少的,比如限制用户在一定时间内发送短信的次数、限制用户在一定时间内请求接口的次数等等。通过限制用户的操作次数,可以避免用户过度使用某个功能或接口,从而保护系统的稳定性和安全性。

    设计与功能

    这个疲劳度模型包含了两个维度的疲劳度配置:全平台维度和userId维度。全平台维度的疲劳度配置是所有用户共享的,而userId维度的疲劳度配置是每个用户单独拥有的。模型中的consume方法用于消耗一个疲劳度,每次调用会检查全平台维度和userId维度的疲劳度是否已经用完。如果还有剩余,则消耗一个疲劳度并返回true;否则返回false。模型中还包含了设置全平台维度和userId维度疲劳度配置的方法。

    用法

    使用这个疲劳度模型非常简单。首先,需要创建一个FatigueModel对象。可以使用默认的配置,也可以自定义配置。然后,在需要限制操作次数的地方调用consume方法,传入userId参数即可。如果consume方法返回true,则说明还有剩余的疲劳度,可以进行操作;如果返回false,则说明疲劳度已经用完,需要等待疲劳度周期结束后才能进行操作。

    编码实现

    用户维度疲劳度模型默认一天20次
    全平台维度的疲劳度默认一天10000次

    package com.eden.core.model;
    
    import lombok.NoArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Objects;
    
    /**
     * 疲劳度模型
     *
     * @author Eden
     */
    @Slf4j
    @NoArgsConstructor
    public class FatigueModel {
    
        /**
         * 全平台维度的疲劳度配置-默认一天10000次
         */
        private int globalLimit = 10000;
        /**
         * 全平台维度的疲劳度配置-疲劳度周期 默认一天
         */
        private long globalPeriod = 24 * 60 * 60 * 1000;
    
        /**
         * 全平台维度的疲劳度配置-当前疲劳度次数
         */
        private int currentGlobalLimit = globalLimit;
        /**
         * 全平台疲劳度周期的开始时间
         */
        private long globalStartTime = System.currentTimeMillis();
    
        /**
         * userId维度的疲劳配置
         */
        private final Map<String, Integer> userLimits = new HashMap<>();
        private final Map<String, Long> userStartTimes = new HashMap<>();
    
        /**
         * userId维度的疲劳配置-默认一天20次
         */
        private int userIdLimit = 20;
    
        /**
         * userId维度的疲劳配置-疲劳度周期为一天
         */
        private long userIdPeriod = 24 * 60 * 60 * 1000;
    
        public FatigueModel(int globalLimit, int userIdLimit) {
            this.globalLimit = globalLimit;
            this.currentGlobalLimit = globalLimit;
            this.userIdLimit = userIdLimit;
        }
    
        public FatigueModel(int globalLimit, long globalPeriod, int userIdLimit, long userIdPeriod) {
            this.globalLimit = globalLimit;
            this.currentGlobalLimit = globalLimit;
            this.globalPeriod = globalPeriod;
            this.userIdLimit = userIdLimit;
            this.userIdPeriod = userIdPeriod;
        }
    
        /**
         * 用户调用一次,消耗一个疲劳度
         */
        public synchronized boolean consume(String userId) {
            // 获取当前时间
            long now = System.currentTimeMillis();
    
            // 更新全平台维度的疲劳度周期
            if (now - globalStartTime >= globalPeriod) {
                // 重置全平台维度的疲劳度
                currentGlobalLimit = globalLimit;
                // 更新全平台疲劳度周期的开始时间
                globalStartTime = now;
            }
    
            // 判断全平台维度的疲劳度是否已经用完
            if (currentGlobalLimit <= 0) {
                log.info(String.format("consume,currentGlobalLimit <= 0,userId=%s,now=%s,currentGlobalLimit=%s,globalStartTime=%s",
                        userId, now, currentGlobalLimit, globalStartTime));
                return false;
            }
    
            // 判断userId维度的疲劳度是否已经用完
            int limit = fetchUserLimit(userId);
            if (limit <= 0) {
                return false;
            }
    
            // 更新全平台维度的疲劳度和userId维度的疲劳度
            currentGlobalLimit--;
            userLimits.put(userId, limit - 1);
            return true;
        }
    
        /**
         * 设置全平台维度的疲劳度配置
         */
        public synchronized void setGlobalLimit(int limit, long period) {
            globalLimit = limit;
            currentGlobalLimit = limit;
            globalPeriod = period;
            globalStartTime = System.currentTimeMillis();
        }
    
        /**
         * 设置userId维度的疲劳度配置
         */
        public synchronized void setUserLimit(String userId, int limit, long period) {
            userLimits.put(userId, limit);
            userStartTimes.put(userId, System.currentTimeMillis() - period);
        }
    
        /**
         * 充值userId维度的疲劳度
         */
        public synchronized void addUserLimit(String userId, int limit) {
            Integer userLimit = userLimits.getOrDefault(userId, this.userIdLimit);
            userLimits.put(userId, userLimit + limit);
        }
    
        /**
         * 获取用户当前剩余疲劳度
         */
        public int fetchUserLimit(String userId) {
            long now = System.currentTimeMillis();
            // 获取用户的疲劳度周期和周期内可用次数
            int limit = userLimits.getOrDefault(userId, userIdLimit);
            Long userStartTime = userStartTimes.get(userId);
            // 判断是否在疲劳度周期内,如果不在则重置周期内可用次数
            if (Objects.isNull(userStartTime) || (now - userStartTime >= userIdPeriod)) {
                userStartTimes.put(userId, now);
                limit = userIdLimit;
                userLimits.put(userId, limit);
            }
            log.info(String.format("fetchUserLimit,userId=%s,now=%s,limit=%s,userStartTime=%s",
                    userId, now, limit, userStartTime));
            return limit;
        }
    
        /**
         * 校验用户疲劳度
         */
        public boolean checkUserLimit(String userId) {
            return fetchUserLimit(userId) > 0;
        }
    }
    

    相关文章

      网友评论

          本文标题:简单疲劳度模型设计(JAVA实现)

          本文链接:https://www.haomeiwen.com/subject/sgnxmdtx.html