首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 實現投票系統:策略模式靈活處理多種投票規則

     編輯:Java 相關知識

投票系統常面臨多種規則(單選、多選、權重、限時等)。本文採用策略模式將投票算法封裝為可互換策略,實現規則與業務流程解耦,支援運行時動態切換投票邏輯。

核心設計

// 1. 策略接口:統一投票行為
public interface VoteStrategy {
    /**
     * 執行投票
     * @param voterId 投票人ID
     * @param optionId 選項ID
     * @param context 上下文(如權重、時間等)
     * @return 投票結果
     */
    VoteResult vote(String voterId, String optionId, VoteContext context);
}

// 2. 上下文對象:攜帶動態參數
public class VoteContext {
    private Map params = new HashMap<>();
    public void put(String key, Object val) { params.put(key, val); }
    public Object get(String key) { return params.get(key); }
}

// 3. 結果封裝
public class VoteResult {
    private boolean success;
    private String message;
    private Map stats; // 實時統計
    // getter/setter/builder 省略
}

具體策略實現

// 單選策略:每人僅能投一票,覆蓋舊選擇
public class SingleChoiceStrategy implements VoteStrategy {
    private final Map votes = new ConcurrentHashMap<>(); // voterId -> optionId
    private final Map stats = new ConcurrentHashMap<>();

    @Override
    public VoteResult vote(String voterId, String optionId, VoteContext ctx) {
        String prev = votes.put(voterId, optionId);
        stats.computeIfAbsent(optionId, k -> new AtomicInteger()).incrementAndGet();
        if (prev != null) {
            stats.computeIfAbsent(prev, k -> new AtomicInteger()).decrementAndGet();
        }
        return VoteResult.success("單選投票成功", snapshot(stats));
    }
}

// 多選策略:每人可投多選項,但每選項限一票
public class MultiChoiceStrategy implements VoteStrategy {
    private final Map> votes = new ConcurrentHashMap<>(); // voterId -> Set
    private final Map stats = new ConcurrentHashMap<>();

    @Override
    public VoteResult vote(String voterId, String optionId, VoteContext ctx) {
        votes.computeIfAbsent(voterId, k -> ConcurrentHashMap.newKeySet()).add(optionId);
        stats.computeIfAbsent(optionId, k -> new AtomicInteger()).incrementAndGet();
        return VoteResult.success("多選投票成功", snapshot(stats));
    }
}

// 權重策略:不同用戶票數權重不同(如 VIP 票值 2)
public class WeightedStrategy implements VoteStrategy {
    private final Map userWeight; // 注入
    private final Map stats = new ConcurrentHashMap<>();

    public WeightedStrategy(Map userWeight) { this.userWeight = userWeight; }

    @Override
    public VoteResult vote(String voterId, String optionId, VoteContext ctx) {
        int w = userWeight.getOrDefault(voterId, 1);
        stats.computeIfAbsent(optionId, k -> new AtomicInteger()).addAndGet(w);
        return VoteResult.success("權重投票成功,權重=" + w, snapshot(stats));
    }
}

投票上下文:策略選擇與執行

public class VoteService {
    private final Map strategies = new HashMap<>();
    private VoteStrategy currentStrategy;

    public VoteService() {
        // 註冊策略
        strategies.put("single", new SingleChoiceStrategy());
        strategies.put("multi", new MultiChoiceStrategy());
        strategies.put("weighted", new WeightedStrategy(loadUserWeights()));
        // 默認策略
        currentStrategy = strategies.get("single");
    }

    public void setStrategy(String strategyKey) {
        VoteStrategy s = strategies.get(strategyKey);
        if (s == null) throw new IllegalArgumentException("未知策略: " + strategyKey);
        this.currentStrategy = s;
    }

    public VoteResult vote(String voterId, String optionId, VoteContext ctx) {
        // 可在此處添加通用校驗:投票時間、用戶狀態、頻率限制等
        return currentStrategy.vote(voterId, optionId, ctx);
    }
}

使用示例

public class Main {
    public static void main(String[] args) {
        VoteService service = new VoteService();
        
        // 單選模式
        service.setStrategy("single");
        service.vote("user1", "optionA", new VoteContext());
        service.vote("user1", "optionB", new VoteContext()); // 覆蓋 A
        
        // 切換多選模式
        service.setStrategy("multi");
        service.vote("user2", "optionA", new VoteContext());
        service.vote("user2", "optionB", new VoteContext()); // 同時生效
        
        // 權重模式
        service.setStrategy("weighted");
        service.vote("vip1", "optionA", new VoteContext()); // 權重 2
    }
}

擴展建議

  • 持久化:策略內 Map 替換為 Redis/DB 操作,保持接口不變。
  • 限流:在 VoteService.vote() 切面攔截,基於 Guava RateLimiter 或 Redis 計數器。
  • 審計日誌:策略執行前後記錄操作日誌,實現可追溯。
  • 組合策略:引入 CompositeStrategy 組合多規則(如「限時+單選」)。

策略模式優勢總結

維度硬編碼 if/else策略模式
新增規則修改核心類,風險高新增類,零修改核心
測試需測全組合單獨測試每策略
運行時切換困難setStrategy() 即時生效
代碼清晰度邏輯糅雜職責單一、易閱讀
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved