桃李春风一杯酒,江湖夜雨十年灯。
1 前言
在前文中已经分享了模板和策略模式的实践SpringBoot-策略和模板模式的思考与实践,在本文中将结合红包算法的场景再次进行实践,主要还是分享红包计算的思考逻辑和心得。在前文中已经介绍了订单拆分的算法,红包的算法和订单的算法有相似的地方。
2 业务分析
对于红包,大家能想到的一定是抢红包的场景,因为这个是一个并发场景且是领取红包的场景,考察的知识点比较多,但是这里介绍的红包业务是需要全面覆盖的,需要从发红包开始,至于红包的领取,会在后续的文章来分享。红包的类型可以分为个人红包和群红包(群红包可以分为平分模式和拼手气模式)
,在本文中将着重介绍拼手气红包的分配算法。
对于平分模式的红包比较简单,采用算术评分是即可,在 java
中会出现除不尽的情况即尾差的问题,则需要使用减法来处理最后一个数据。
对于拼手气模式的红包,相对来说比较复杂一点,既要保证红包分配的均匀性,也要考虑到红包之间的差异,还有一个红包最小金额的问题。假设需要发 n
个红包,在计算第 i
个红包的随机金额时,随机数的范围最小值即红包的最小金额,最大金额的设置要保证至少有 (n - i)
个红包最小金额。即便是如此,也不能保证一次循环就可以得到所有的红包金额,所以还需要设置本次要分的最大金额要小于未分配金额的 m
倍,这样才可以保证一次循环分配所有的红包金额。
css
# 假设需要分配 n 个红包红包分配总金额为 m ,红包分配的最小金额为 0.1 ,则每次分配的最小金额为 0.01
第i次要分配的红包金额随机数取数范围为
amt = [0.01,(m -p - 0.01*(n-i)) * 0.66]
p 为第 i 次已经分配的红包总金额
如果本次分配最大金额为剩余待分配金额的 k 倍,则系数为 k/(k +1 ), 0.66 即表示2倍,倍数越大,红包的极值差越大,否则就越小
3 红包算法
红包平分模式的算法比较简单,需要按照比例来计算每个红包的金额,在 java 编程中但凡涉及到除法,都会存在除不尽的情况,所以最后一个一定要使用减法,才能保证子单和主单的金额一致性
。
3.1 红包平分算法
红包平均算法就是使用算术平均方法,在 java
中对于四则运算中的除法需要考虑结果的保留位数,否则遇到除不尽的情况会报 Invalid rounding mode
的错误。最后一个红包需要使用减法来计算,否则单个红包的累计之和红包总金额不一致。在操作计算时,可以使用 hutools
中的 Numutils
工具类进行计算,可以很方便的实现计算。
3.2 拼手气算法
红包拼手气的算法如下图所示,核心的逻辑还是计算每个红包的具体金额,保证每个红包的差异性,也要保证红包间的均衡性。这里使用的是 N
倍余额算法。在计算过程中可以使用 Numutils
工具类实现便捷计算。
7 总结
在本文中,主要介绍了发红包的类型和红包算法的实现,在后续文章中将使用策略模式来实现红包的发放和领取,通过红包的业务增强了对订单金额计算深刻的认知,也拓展巩固了作者的业务理解,同时也对设计模式有了新的感悟和心得。项目 github
地址 springboot-auth。