根據(jù)很多需求的使用場(chǎng)景,如發(fā)紅包、砍價(jià)類需求,這兩個(gè)功能都有一個(gè)同樣的特點(diǎn),如下:
紅包
1.總金額
2.紅包個(gè)數(shù)
3.最小紅包數(shù)量
砍價(jià)
1.砍價(jià)總金額
2.需要多少人完成砍價(jià)(人數(shù)根據(jù)需求而定)
- 固定砍價(jià)人數(shù)
- 隨機(jī)砍價(jià)人數(shù)
- 指定隨機(jī)砍價(jià)人數(shù)
第2點(diǎn)三個(gè)規(guī)則都需要根據(jù)規(guī)則得出一個(gè)人數(shù)
3.最小砍價(jià)金額
開發(fā)思路
驗(yàn)證參數(shù)
最小金額不允許小于0
總金額不允許大于數(shù)量乘最小金額
分配金額
取得平均金額(總金額/剩余數(shù)量)
分配金額 平均金額
小于等于
最金額時(shí)直接分配最小金額
獲取金額幅度比例
最小值不允許小于-1
最大值不允許大于1
得出分配金額 幅度計(jì)算(平均值*(1+幅度比例
))
分配金額判斷分配金額
小于最小金額
或者分配金額
大于可領(lǐng)取最大金額
((最小金額+剩余總金額)- (剩余數(shù)量×最小金額))時(shí) 重新分配金額
剩余最后一個(gè)則剩余所有金額都分配
開發(fā)代碼
<?php /** * 發(fā)送紅包 * Class sandRed */ class sandRed { #紅包金額 protected $amount; #紅包個(gè)數(shù) protected $num; #領(lǐng)取的紅包最小金額 protected $minAmount; #紅包分配結(jié)果 protected $amountArr = []; public function __construct($amount, $num = 1, $minAmount = 1) { $this->amount = $amount; $this->num = $num; $this->minAmount = $minAmount; } /** * 處理返回 * @return array * @throws Exception */ public function handle() { # 驗(yàn)證 if ($this->amount < $validAmount = $this->minAmount * $this->num) { throw new Exception('紅包總金額必須≥'.$validAmount.'元'); } # 分配紅包 $this->allot(); return $this->amountArr; } /** * 分配紅包 */ protected function allot() { # 剩余可分配的紅包個(gè)數(shù) $num = $this->num; # 剩余可領(lǐng)取的紅包金額 $amount = $this->amount; while ($num >= 1) { if ($num == 1) { # 剩余一個(gè)的時(shí)候,直接取剩余紅包 $coupon_amount = $this->formattingAmount($amount); } else { # 平均金額 $avgAmount = $this->formattingAmount($amount / $num); # 分配金額 $countAllotAmount = $this->countAllotAmount($avgAmount, $amount, $num); # 剩余的紅包的平均金額 $coupon_amount = $this->formattingAmount($countAllotAmount); } # 追加分配金額 $this->amountArr[] = $coupon_amount; # 計(jì)算剩余金額 $amount -= $coupon_amount; $num--; } # 隨機(jī)打亂 // shuffle($this->amountArr); } /** * 計(jì)算分配的紅包金額 * @param float $avgAmount 每次計(jì)算的平均金額 * @param float $amount 剩余可領(lǐng)取金額 * @param int $num 剩余可領(lǐng)取的紅包個(gè)數(shù) * @return float */ protected function countAllotAmount($avgAmount, $amount, $num) { # 如果平均金額小于等于最低金額,則直接返回最低金額 if ($avgAmount <= $this->minAmount) { return $this->minAmount; } # 浮動(dòng)比率 $floatingRate = $this->floatingRate(); # 分配金額 $allotAmount = $avgAmount * (1 + $floatingRate); # 浮動(dòng)計(jì)算 $coupon_amount = $this->formattingAmount($allotAmount); # 如果低于最低金額或超過(guò)可領(lǐng)取的最大金額,則重新獲取 if ($coupon_amount < $this->minAmount || $coupon_amount > $this->canReceiveMaxAmount($amount, $num)) { return $this->countAllotAmount($avgAmount, $amount, $num); } return $coupon_amount; } /** * 計(jì)算分配的紅包金額-可領(lǐng)取的最大金額 * @param $amount * @param $num * @return float|int */ protected function canReceiveMaxAmount($amount, $num) { return $this->minAmount + $amount - $num * $this->minAmount; } /** * 紅包金額浮動(dòng)比例 * @return float|int */ protected function floatingRate() { # 60%機(jī)率獲取剩余平均值的大幅度紅包(可能正數(shù)、可能負(fù)數(shù)) if (rand(1, 100) <= 60) { # 上下幅度70% return rand(-70, 70) / 100; } # 其他情況,上下浮動(dòng)30%; return rand(-30, 30) / 100; } /** * 格式化金額,保留2位 * @param $amount * @return string */ protected function formattingAmount($amount) { return sprintf('%01.2f', round($amount, 2)); } }
- 總金額
$amount = 1;
- 分配數(shù)量
$num = 10;
- 最小金額
$minAmount = 0.01; $red = new sandRed($amount, $num, $minAmount); $res = $red->handle(); print_r($res);
- 輸出結(jié)果 [0.10,0.04,0.08,0.04,0.16,0.14,0.11,0.13,0.11,0.09]
echo array_sum($res);
- 輸出結(jié)果 1
推薦學(xué)習(xí):《PHP視頻教程》