Enums
通常 SWITCH 會被用於需要大量使用 if-else 的情境, 在某些時候加入 enums 的設計, 可以讓 switch 更容易被理解與管理.
enum Player { WARRIOR, ARCHER, WIZARD, }
|
String swordAttack() { return "劍術攻擊"; }
String shootAttack() { return "射箭攻擊"; }
String fireAttack() { return "火焰攻擊"; }
String attack(Player player) { switch(player) { case WARRIOR: return this.swordAttack();
case ARCHER: return this.shootAttack();
case WIZARD: return this.fireAttack();
default: throw new IllegalArgumentException("Invalid player: " + player); } }
|
Supplier
Supplier
是 java8+ 的 lambda 滿好用的特性之一, 我通常會用它來封裝一些無參數傳入的 methods, 封裝到 Supplier 的 method, 並不會馬上被執行, 在某些層面上也算是一種 lazy loading 的應用, SWITCH 就可以簡單被改寫成:
String attack(Player player) { switch(player) { case WARRIOR: Supplier<String> warriorSupplier = () -> this.swordAttack(); return warriorSupplier.get();
case ARCHER: Supplier<String> archerSupplier = () -> this.shootAttack(); return archerSupplier.get(); case WIZARD: Supplier<String> wizardSupplier = () -> this.fireAttack(); return wizardSupplier.get(); default: throw new IllegalArgumentException("Invalid player: " + player); } }
|
Map
上述的寫法, 其實與原本的 SWITCH 寫法沒差多少, 要應用 java8+ lambda 的 Stream 特性, 可能需要把這些條件判斷搜集起來, 藉由 MAP
的 KEY-VALUE 的特性, 讓 Stream 可以串接起來, 並透過 KEY 去篩選 Enums.
String attack(Player player) { Map<Player, Supplier<String>> attackMap = new HashMap(); attackMap.put(Player.WARRIOR, () -> this.swordAttack()); attackMap.put(Player.ARCHER, () -> this.shootAttack()); attackMap.put(Player.WIZARD, () -> this.fireAttack());
final Map<Player, Supplier<Void>> map = Collections.unmodifiableMap(attackMap);
map.entrySet().stream() .filter(entry -> player.equals(entry.getKey())) .map(Entry::getValue) .map(Supplier::get) .findFirst() .orElseThrow(() -> new IllegalArgumentException("Invalid type: " + type)); }
|
Optimize
然而都已經是 MAP 的資料結構了, 其實可以讓時間複雜度降低為 O(1)
, 可以捨棄 Stream
優化改寫為:
String attack(Player player) { Map<Player, Supplier<String>> attackMap = new HashMap(); attackMap.put(Player.WARRIOR, () -> this.swordAttack()); attackMap.put(Player.ARCHER, () -> this.shootAttack()); attackMap.put(Player.WIZARD, () -> this.fireAttack());
final Map<Player, Supplier<String>> map = Collections.unmodifiableMap(attackMap);
return Optional.ofNullable(map.get(player)) .orElseThrow(() -> new IllegalArgumentException("Invalid type: " + player)); }
|