zoukankan      html  css  js  c++  java
  • 多条件拦截链如何实现?

    问题提出

    1. 用户参与抽奖,每日只能参与3次,总共只能参与15次,如何控制?(限额)

    2. 给用户发送短信,每天只能发送3条,每条间隔10分钟,如何控制?(防骚扰)

    • 两个问题其实类似 ,都是多个限制条件

    以问题2制定方案

    • 使用redis做计数器,使用StringRedisTemplate作为API
    • 使用两个校验器分别校验两个约束
    • 后续添加规则只需要新增校验器
    • 以【dayLimit:用户ID】为key,自增value,如果自增后的值大于3,返回false,否则返回true;过期时间设置为次日0点
    • 以【periodLimit:用户ID】为key,当前时间为value,过期时间设置为10分钟,使用setIfAbsent进行设置。如果设置成功,说明10分钟内没有发送过。如果设置失败,说明10分钟内发送过,获取key的剩余过期时间为短信需要延时时间。

    存在问题

    • 第一步如果成功,第二步失败,那么白白消耗了一次每日的限制,需要回滚
    • 如果在第二步失败回滚,那么需要在校验器2里面回滚校验器1,两个步骤产生了强行关联!
    • 校验器1必须在校验器2前面
    • 添加了校验器3,那么就要回滚1和2

    如何解决?

    • 合并成一个校验器:优点:类之间不存在依赖性;缺点:不符合开闭原则,比如添加一个规则7天只能发10条,需要继续往这个校验器里面加代码

    • 使用redis的lua脚本,优点:降低了类的依赖性;缺点:逻辑在脚本里面

    • emmmm,好像没有很好的解决方案,这种依赖和回滚必然存在

    最后思考

    • 不依赖事务就只能自己回滚了,那就尽量设计下类结构吧
    • 还是按照一个规则一个校验器来写
    • 接口声明校验方法和回滚方法,由具体校验器来实现
    • 接口还要一个getPrevious方法,返回上一个校验器
    • 所有的校验器使用责任链的方式串起来,每个校验器提供一个回滚方法,该方法在下一个校验器不通过时调用,同时,每个校验器还要通过getPrevious调用上一个校验器的回滚方法,达到递归回滚的目的
    • 使用抽象校验器实现getPrevious和调用上一个校验器
    • 这样设计后,每个校验器只需要专注实现自己的校验逻辑以及回滚逻辑
    • 校验器的顺序起来不用必须固定了!
    • emmmm,看起来也符合了开闭原则!

    最后的问题

    • 事务,某个校验器执行中宕机,无法回滚。记好日志吧,低概率高成本低损失不值得修复。

    收获

    • 最后思考里的设计本来没想到的,打字打到这里突然灵光乍现!解决了多重回滚问题。
    • 写代码的时候发现我的校验器是使用Sping注入到List里面的,调用是通过遍历调用的,那么其实顺序就有了,没有责任链方式的previous关系了
    • 即如果校验器是使用List保存的,那么getPrevious也可以不要了,遍历list的时候使用下标方式,回滚的时候回滚遍历过的校验器就行了

    思考<笔记<动手

  • 相关阅读:
    数学趣题——数字的全排列
    数学趣题——谁在说谎
    数学趣题——移数字游戏
    数学趣题——魔幻方阵
    数学趣题——亲密数
    数学趣题——数字翻译器
    数学趣题——求圆周率的近似值
    数学趣题——完全数
    Linux:CentOS 7 连接ssh方法
    Linux:CentOS 7 服务器之间ssh无密码登录、传输文件
  • 原文地址:https://www.cnblogs.com/zby9527/p/13256454.html
Copyright © 2011-2022 走看看