在開發過程中,常會遇到需要根據指定機率執行不同邏輯的場景。例如:20% 執行方法 A、1% 執行方法 B、29% 執行方法 C、50% 執行方法 D。若直接使用 if-else 搭配隨機數判斷,程式碼不僅冗長,還難以維護擴展。本文介紹一個通用的 RandomDispatcher 類別,讓權重分發邏輯變得簡潔優雅。
分發器內部維護一個「權重-索引」映射表。隨機時產生一個 0 到總權重之間的數值,遍歷累加權重區間,落在哪個區間就回傳對應的索引。這樣無需硬編碼機率邏輯,新增或調整權重只需修改配置。
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class RandomDispatcher {
private final List<WeightEntry> entries = new ArrayList<>();
private int totalWeight = 0;
private final Random random = new Random();
/** 內部靜態類別:封裝權重與業務索引 */
private static class WeightEntry {
int weight;
int index;
WeightEntry(int weight, int index) {
this.weight = weight;
this.index = index;
}
}
/** 新增一個權重項目
* @param weight 權重值(不需加總為 100)
* @param index 業務邏輯對應的索引碼
*/
public void put(int weight, int index) {
if (weight <= 0) return;
entries.add(new WeightEntry(weight, index));
totalWeight += weight;
}
/** 執行隨機分發,回傳對應的索引碼 */
public int random() {
if (entries.isEmpty()) return -1;
int r = random.nextInt(totalWeight); // 0 ~ totalWeight-1
int cumulative = 0;
for (WeightEntry e : entries) {
cumulative += e.weight;
if (r < cumulative) return e.index;
}
return entries.get(entries.size() - 1).index; // 兜底
}
}
public class Demo {
public static void main(String[] args) {
RandomDispatcher dispatcher = new RandomDispatcher();
// 配置權重:索引 1~4 分別代表四種業務
dispatcher.put(20, 1); // 20% -> A
dispatcher.put(1, 2); // 1% -> B
dispatcher.put(29, 3); // 29% -> C
dispatcher.put(50, 4); // 50% -> D
// 模擬 10 次分發
for (int i = 0; i < 10; i++) {
int idx = dispatcher.random();
switch (idx) {
case 1: System.out.println("執行方法 A"); break;
case 2: System.out.println("執行方法 B"); break;
case 3: System.out.println("執行方法 C"); break;
case 4: System.out.println("執行方法 D"); break;
default: System.out.println("無匹配邏輯");
}
}
}
}
put(),無須修改核心演算法。此模式廣泛適用於遊戲掉落、廣告輪播、A/B 測試流量分發等場景,建議收藏備用。