策略模式將演算法族群封裝為可互換的策略類別,讓客戶端在執行期動態選擇行為,避免龐大的 if-else 或 switch。本文以「圖片儲存格式選擇」為例,展示標準實作與現代化改良。
save()。// 1. 策略介面
public interface ImageSaver {
void save();
}
// 2. 具體策略
public class GIFSaver implements ImageSaver {
@Override public void save() { System.out.println("儲存為 GIF 格式"); }
}
public class JPEGSaver implements ImageSaver {
@Override public void save() { System.out.println("儲存為 JPEG 格式"); }
}
public class PNGSaver implements ImageSaver {
@Override public void save() { System.out.println("儲存為 PNG 格式"); }
}
// 3. Context:策略選擇與委派
public class TypeChooser {
public static ImageSaver getSaver(String type) {
switch (type.toUpperCase()) {
case "GIF": return new GIFSaver();
case "JPEG": return new JPEGSaver();
case "PNG": return new PNGSaver();
default: throw new IllegalArgumentException("不支援格式: " + type);
}
}
}
// 4. 客戶端使用
public class User {
public static void main(String[] args) {
ImageSaver saver = TypeChooser.getSaver("GIF");
saver.save(); // 輸出: 儲存為 GIF 格式
}
}
利用 Map 消除 switch,支援熱插拔:
public class TypeChooserV2 {
private static final Map> REGISTRY = new HashMap<>();
static {
REGISTRY.put("GIF", GIFSaver::new);
REGISTRY.put("JPEG", JPEGSaver::new);
REGISTRY.put("PNG", PNGSaver::new);
}
public static ImageSaver getSaver(String type) {
Supplier supplier = REGISTRY.get(type.toUpperCase());
if (supplier == null) throw new IllegalArgumentException("不支援: " + type);
return supplier.get();
}
// 支援運行期註冊新格式 (如外掛機制)
public static void register(String type, Supplier supplier) {
REGISTRY.put(type.toUpperCase(), supplier);
}
}
@Component
public class ImageSaverFactory {
private final Map savers = new HashMap<>();
@Autowired
public ImageSaverFactory(List saverList) {
for (ImageSaver s : saverList) {
String key = s.getClass().getSimpleName().replace("Saver", "").toUpperCase();
savers.put(key, s);
}
}
public ImageSaver getSaver(String type) {
ImageSaver s = savers.get(type.toUpperCase());
if (s == null) throw new IllegalArgumentException("不支援: " + type);
return s;
}
}
// 每個策略獨立 Bean
@Component("GIF") public class GIFSaver implements ImageSaver { ... }
@Component("JPEG") public class JPEGSaver implements ImageSaver { ... }
@Component("PNG") public class PNGSaver implements ImageSaver { ... }
| 模式 | 核心意圖 | 關鍵差異 |
|---|---|---|
| 策略模式 | 演算法可互換,客戶端主動選擇 | 策略之間平行無關,Context 不持有狀態 |
| 狀態模式 | 物件行為隨內部狀態改變 | 狀態轉換通常由 Context 或 State 內部控制 |
| 模板方法 | 定義演算法骨架,子類實作細節 | 繼承關係,編譯期固定流程 |
若以上均符合,策略模式是最佳選擇。