前幾天,我更新了一個十分有趣的發紅包案例:普通紅包案例
今天,我對它進行了改進和更新
使它能夠真正模擬現實生活中社交環境下的發紅包場景!
分析:
在現實生活中,往往發手氣紅包比發普通紅包的頻率要大很多,而且,當人們點擊拼手氣紅包時的樂趣也遠遠高於普通紅包,人們在獲得不同收益的同時,也在比較別人的手氣,那麼,真正是自己或者別人在開紅包的手氣好嗎,還是另有原因呢?
其實,這都與我們所學過的隨機數有很大原因!
在這個案例中,和上次一樣,我們設想羣主發紅包自己是不能搶的,在剩下的羣成員中,大家可以隨機選擇一個紅包,爲了真實模擬,我們做兩次模擬:
第一次:發紅包的個數剛好與羣成員個數相同,即每個人都可以獲得一個紅包,且紅包的大小不少於0.01元;
第二次:發紅包的個數少於羣成員,即不是每個人都能獲得紅包,其中有人開出的是空包。
金額是隨機的,但是最多的不能太多,不超過總金額的一半(這是生活中搶紅包幾乎99.9%的概率下發生的,不考慮極端情況),羣主在發完錢後,羣成員在收到紅包後更新錢包。
實現:
首先,我們定義用戶類User:
其中有用戶名和餘額,還有相應構造方法。
public class User {
// 成員變量
private String username; // 用戶名
private double leftMoney; // 餘額,有角和分
// 構造方法
public User() {
}
public User(String username, double leftMoney) {
this.username = username;
this.leftMoney = leftMoney;
}
// get/set方法
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public double getLeftMoney() {
return leftMoney;
}
public void setLeftMoney(double leftMoney) {
this.leftMoney = leftMoney;
}
// 展示信息的方法
public void show() {
System.out.println("用戶名:"+ username +" , 餘額爲:" + leftMoney + "元");
}
}
其次,定義羣主類Manager:
對double類型小數點後兩位數提供了全新的解決方案;
思路明晰:對於發送紅包個數是否滿足羣成員需求寫出解決方案:當個數不足時,在紅包中加入等量空包,以滿足需求。
public class Manager extends User {
// 添加構造方法
public Manager() {
}
public Manager(String username, double leftMoney) {
// 通過super 調用父類構造方法
super(username, leftMoney);
}
public ArrayList<Double> send(double money, int count) {
// 獲取羣主餘額
double leftMoney = getLeftMoney();
// 如果發出去的紅包大於羣主剩餘錢,則發送失敗
if(money > leftMoney) {
System.out.println("餘額不足!");
return null;
}
// 創建一個集合,保存等份金額
ArrayList<Double> list = new ArrayList<>();
// 改進!解決小數後兩位問題
double managerLast =(double)Math.round((leftMoney - money) * 100) / 100;
super.setLeftMoney(managerLast);
// 擴大100倍,相當於折算成'分'爲單位,避免小數運算損失精度的問題
money *= 100;
// 生成隨機數
Random r = new Random();
// 保存剩餘的金額以及計算分發出去紅包的份數
int leftmoney = (int) money;
int leftconut = count;
// 隨機分配金額,每次分配的金額不大於總金額的50%,並將所分配的金額加入list紅包中
for (int i = 0; i < count - 1; i++) {
int setmoney = r.nextInt(leftmoney / leftconut * 2 ) + 1;
double moneySetdouble = (double) Math.round(setmoney) / 100;
list.add(moneySetdouble);
leftmoney -= setmoney;
leftconut --;
}
// 改進!解決小數後兩位問題
double moneySetdouble = (double) Math.round(leftmoney) / 100;
list.add(moneySetdouble);
// 當紅包個數不能滿足分發的需求時,在紅包list中添加空包
if(count<5){
while(count++<5) {
list.add(0.0);
}
}
// 返回集合
return list;
}
}
然後,我們定義成員類Member:
思路明晰:更新成員餘額:通過成員隨機選取一個紅包的方式,那麼就很好地避免了前面的人能拿到有金額的紅包,後面的人只能拿到空包的問題,用一種隨機的方式來控制羣成員拿紅包的先後順序,即拿到有金額的搶到紅包,空包的視爲沒有搶到紅包。
public class Member extends User {
public Member() {
}
public Member(String username, double leftMoney) {
super(username, leftMoney);
}
// 打開紅包,就是從集合中,隨機取出一份,保存到自己的餘額中
public void receive(ArrayList<Double> list) {
// 創建一個Random對象,隨機生成一個紅包編號
int index = new Random().nextInt(list.size());
// 從集合中移去相應編號,得到該編號的金額的紅包
double delta = list.remove(index);
// 當前成員本來有多少錢
double money = super.getLeftMoney();
// 改進!解決小數後兩位問題
double last = (double) Math.round((money + delta) * 100) / 100;
// 直接調用父類方法,設置到餘額
super.setLeftMoney(last);
}
}
最後,寫執行程序,main函數執行:
先創建定義成員,顯示原信息,然後羣主發紅包,羣成員搶紅包,最後公佈搶紅包結果。
public class mainRedPacket {
public static void main(String[] args) {
// 創建一個羣主對象,五個成員
Manager manager = new Manager("羣主", 266.66);
Member one = new Member("成員A",105.63);
Member two = new Member("成員B",5.62);
Member three = new Member("成員C",0);
Member four = new Member("成員D",23.4);
Member five = new Member("成員E",3.21);
// 顯示原始成員的餘額
manager.show();
one.show();
two.show();
three.show();
four.show();
five.show();
System.out.println("==================");
// 創建鍵盤錄入紅包金額和紅包個數
Scanner sc = new Scanner(System.in);
System.out.println("請輸入發送紅包的金額:");
double money= sc.nextDouble();
System.out.println("請輸入發送紅包的份數:");
int count = new Scanner(System.in).nextInt();
ArrayList<Double> list = manager.send(money,count);
System.out.println("==================");
// 顯示紅包內的金額數(上帝視角)
System.out.println("紅包爲:" + list);
// 開始搶紅包
one.receive(list);
two.receive(list);
three.receive(list);
four.receive(list);
five.receive(list);
// 搶到紅包,顯示餘額信息
manager.show();
one.show();
two.show();
three.show();
four.show();
five.show();
}
}
結果展示:
第一種情況:發紅包的個數剛好與羣成員個數相同,即每個人都可以獲得一個紅包,且紅包的大小不少於0.01元。
第二種情況:發紅包的個數少於羣成員,即不是每個人都能獲得紅包,其中有人開出的是空包。
第三種情況:餘額不足,羣主未能發紅包!
至此,三種情況均能成功演示!
思考:
在異常處理上沒有很好地下功夫,還可以改進;
讀者還可以製作用戶圖形界面,更生動形象地展示整個流程;
在分發紅包上還有一種多線程的處理方式也可以加以運用,讀者可以自行嘗試解決,博主不再進行演示。
感謝您的閱讀,不足之處歡迎指正!