java 实现随机派发红包

这篇博客展示了如何使用Java实现一个简单的群聊红包分配功能。通过定义`User`、`Lord`(群主)和`Member`(群员)类,实现了红包的发放和领取。群主通过`send`方法发红包,红包金额由`SplitBigDecimalUtils`工具类随机分配。测试类`TestRedPackage`演示了整个流程,包括群主发红包、群员领红包及余额检查。代码中包含了数据校验和随机金额生成策略。
摘要由CSDN通过智能技术生成

新年到,发红包,下面是java 简单实现群主派发红包的功能:具体实现代码如下:
定义用户主类:

package com.example.demo.redEnvelopes;

import java.math.BigDecimal;

/**
 * 用户主类
 */
public class User {
    // 定义两个私有属性
    private String name;
    private BigDecimal leftMoney;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public BigDecimal getLeftMoney() {
        return leftMoney;
    }

    public void setLeftMoney(BigDecimal leftMoney) {
        this.leftMoney = leftMoney;
    }

    public User() {
    }

    public User(String name, BigDecimal leftMoney) {
        this.name = name;
        this.leftMoney = leftMoney;
    }

    // 定义一个查看余额的方法
    public void check() {
        System.out.println("名字:" + name + ",余额为" + leftMoney + "元");
    }

}

定义群主类:

package com.example.demo.redEnvelopes;

import org.apache.commons.compress.utils.Lists;

import java.math.BigDecimal;
import java.util.List;

/**
 * 定义群主类
 */
public class Lord extends User{

    /**
     * 每个红包总额最小金额
     */
    private static final BigDecimal  MIN = new BigDecimal("0.01");

    /**
     * 精度
     */
    private static final int  SCALE = 2;

    public Lord() {
    }

    public Lord(String name, BigDecimal leftMoney) {
        // super(参数列表) 永远要放到构造方法中的第一条语句中
        super(name, leftMoney);
    }


    /**
     * 发红包
     * 群主发红包,就是把一个整数的全额分成若干等份
     *      1.获取群主的余额,是否具备发红包的能力不能发红包则返回一个null,并且提示:"余额不足!"
     *      2.修改群主的余额,此时群主的余额 = 原来的余额 - 发的红包的额度
     *      3.拆分红包
     *           随机分配红包金额
     */
    public List<BigDecimal> send(BigDecimal money,int count){
        List<BigDecimal> list= Lists.newArrayList();
        // 数据的合法性检验
        // 获取群主的余额
        BigDecimal leftMoney=super.getLeftMoney();
        // 判断是否具备发红包的能力
        if (leftMoney.compareTo(money)<0) {
            System.out.println("余额不足");
            return list;
        }
        // 修改群主余额
        super.setLeftMoney(leftMoney.subtract(money));

        // 发红包
        list=SplitBigDecimalUtils.splitBigDecimalFromRange(money,count,SCALE,MIN,money.subtract(MIN));
        return list;
    }


}

定义普通群员类

package com.example.demo.redEnvelopes;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

//定义普通群员类
public class Member extends User {

    public Member() {
    }

    public Member(String name, BigDecimal leftMoney) {
        super(name, leftMoney);
    }

    // 收红包   receive
    public void receive(List<BigDecimal> list) {
        // 构造一个随机类对象 Random
        Random r = new Random();
        // 随机一个数是list容器中的索引  索引的取值范围 [0,list.size()]
        int index = r.nextInt(list.size());
        // 当去取一个红包,那么list容器中就要少一个红包
        BigDecimal money = list.remove(index);
        // 普通成员的余额需要增加对应的值
        super.setLeftMoney(super.getLeftMoney().add(money));
        System.out.println(getName()+"拆到了:"+getLeftMoney());
    }
}

红包随机金额工具类

package com.example.demo.redEnvelopes;

import org.apache.commons.compress.utils.Lists;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

/**
 * 随机分配红包
 */
public class SplitBigDecimalUtils {

    /**
     * 红包总额最小金额,单位为与scale有关,例如scale为2,单位为分
     */
    private static final BigDecimal  MIN_MONEY = new BigDecimal("0.01");
    /**
     * 红包总额最大金额
     */
    private static final BigDecimal MAX_MONEY = new BigDecimal("200");

    /**
     * 红包金额的离散程度,值越大红包金额越分散
     */
    private static final double DISPERSE = 1;

    private static final BigDecimal pow = new BigDecimal(10);


    /**
     * 将一个BigDecimal 切分成指定个数指定精度指定范围的若干个数,如果范围设置不当,前面随机的数较小,可能会导致最后一个数过大超出范围
     * @param amount 总数量
     * @param count 总个数
     * @param scale 精度
     * @param min 单个红包最小值
     * @param max 单个红包最大值
     * @return
     */
    public static List<BigDecimal> splitBigDecimalFromRange(BigDecimal amount, int count, int scale, BigDecimal min, BigDecimal max) {
        BigDecimal total = BigDecimal.ZERO;
        if(amount.compareTo(MAX_MONEY)>0){
            System.out.println("红包金额超过最大限额");
            return new ArrayList<BigDecimal>();
        }
        if(amount.compareTo(MIN_MONEY)<0){
            System.out.println("红包金额不能低于最低限额");
            return new ArrayList<BigDecimal>();
        }
        System.out.println("群主发红包了,红包数量:"+count);
        List<BigDecimal> list = Lists.newArrayList();
        for (int i = 0; i < count; i++) {
            BigDecimal tem = getOneRedBag(amount.subtract(total), count - i, scale, min, max);
            total = total.add(tem);
            list.add(tem);
        }
        return list;
    }

    public static void main(String[] args) {
        //总量
        BigDecimal amount = new BigDecimal(20);
        System.out.println(MAX_MONEY.compareTo(amount));
        BigDecimal min = new BigDecimal(0.01);
        BigDecimal max = amount.subtract(min);

        List<BigDecimal> bigDecimals = splitBigDecimalFromRange(amount, 4, 2, min, max);
        System.out.println(bigDecimals);
    }


    private static BigDecimal getOneRedBag(BigDecimal amount, int count, int scale, BigDecimal min, BigDecimal max) {
        // 转成int做运算
        int amountInt = amount.setScale(scale, RoundingMode.HALF_UP).multiply(pow).intValue();
        int minInt = min.setScale(scale, RoundingMode.HALF_UP).multiply(pow).intValue();
        int maxInt = max.setScale(scale, RoundingMode.HALF_UP).multiply(pow).intValue();
        if (amountInt < minInt * count) {
            throw new RuntimeException("最小值设置过大");
        }
        if (minInt > maxInt){
            throw new RuntimeException("最大值小于最小值");
        }
        if (maxInt * count < amountInt){
            throw new RuntimeException("最大值设置过小");
        }
        //最大值不能大于总金额
        maxInt = maxInt > amountInt ? amountInt : maxInt;
        //randomBetweenMinAndMax()上面有这个方法
        return new BigDecimal(randomBetweenMinAndMax(amountInt, count, minInt, maxInt)).divide(pow, scale,
                RoundingMode.HALF_UP);
    }

    /**
     * 在最小值和最大值之间随机产生一个
     *
     * @param money
     * @param count
     * @param min   : 最小量
     * @param max   : 最大量
     * @return
     */
    public static int randomBetweenMinAndMax(int money, int count, int min, int max) {
        //最后一个直接返回
        if (count == 1) {
            return money;
        }
        //最小和最大金额一样,返最小和最大值都行
        if (min == max) {
            return min;
        }
        //最小值 == 均值, 直接返回最小值
        if (min == money / count) {
            return min;
        }
        //min<=随机数bag<=max
        int bag = ((int) Math.rint(Math.random() * (max - min) + min));

        //剩余的均值
        int avg = (money - bag) / (count - 1);
        //比较验证剩余的还够不够分(均值>=最小值 是必须条件),不够分的话就是最大值过大
        if (avg < 1) {
            /*
             * 重新随机一个,最大值改成本次生成的量
             * 由于 min<=本次金额bag<=max, 所以递归时bag是不断减小的。
             * bag在减小到min之间一定有一个值是合适的,递归结束。
             * bag减小到和min相等时,递归也会结束,所以这里不会死递归。
             */
            return randomBetweenMinAndMax(money, count, min, bag);
        } else {
            return bag;
        }
    }


}

测试类

package com.example.demo.redEnvelopes;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

//测试类
public class TestRedPackage {

    public static void main(String[] args) {
        //构建一个群主
        //构建多个成员对象
        Lord lord = new Lord("小明", new BigDecimal(1000));
        Member m1 = new Member("小王", BigDecimal.ZERO);
        Member m2 = new Member("小刘", BigDecimal.ZERO);
        Member m3 = new Member("小孙", BigDecimal.ZERO);
        // 发红包了
       List<BigDecimal> list = lord.send(new BigDecimal("200"), 3);
        // 查看群主的余额
        lord.check();
        // 加一个判断 群主确定发出了红包
        if (list.size() == 0) {
            System.out.println("群主发红包失败了,再来");
        } else {
            // 普通成员收红包
            m1.receive(list);
            m1.check();
            m2.receive(list);
            m2.check();
            m3.receive(list);
            m3.check();
        }

    }

}

运行查看结果
在这里插入图片描述

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值