在日常 Java 開發中,針對狀態或類型進行判斷時,switch-case 與 if-else 是最直觀的寫法。然而,隨著業務邏輯增長,這類條件分支往往會膨脹成難以維護的「箭頭型代碼」。在物件導向的世界裡,我們有兩套經典方案能優雅地消除這些判斷:繼承多態與狀態模式。兩者的核心思想都是利用物件的間接引用,將條件分支分散到各個具體類別中,實現「開閉原則」——對擴展開放,對修改關閉。
假設我們有一個 Method 類別,需根據型別(POST、GET、PUT、DELETE)執行不同邏輯:回傳描述字串、判斷是否為安全方法、判斷是否需要密碼。原始寫法如下:
public class Method {
private int _type;
public static final int POST = 0, GET = 1, PUT = 2, DELETE = 3;
public Method(int type) { _type = type; }
public String getMethod() {
switch (_type) {
case POST: return "This is POST method";
case GET: return "This is GET method";
case PUT: return "This is PUT method";
case DELETE: return "This is DELETE method";
default: throw new NoMethodTypeException();
}
}
public boolean safeMethod() { return _type == GET; }
public boolean passwordRequired() { return _type != POST; }
}
這裡存在一個 switch 和兩個 if-else,每次新增 HTTP 方法都必須修改這三個地方,違反單一職責原則。
若一個 Method 物件一旦建立,其型別就不再改變,繼承多態是最自然的選擇。我們將 Method 定義為抽象基類,四種 HTTP 方法各自對應一個子類別:

public abstract class Method {
// 靜態工廠方法,隱藏具體子類別建立細節
public final static Method createPostMethod() { return new PostMethod(); }
public final static Method createGetMethod() { return new GetMethod(); }
public final static Method createPutMethod() { return new PutMethod(); }
public final static Method createDeleteMethod(){ return new DelMethod(); }
abstract public String getMethod();
// 預設實現符合大多數子類別,少數例外再 override
public boolean safeMethod() { return false; }
public boolean passwordRequired() { return true; }
}
public class PostMethod extends Method {
@Override public String getMethod() { return "This is POST method"; }
@Override public boolean passwordRequired() { return false; }
}
public class GetMethod extends Method {
@Override public String getMethod() { return "This is GET method"; }
@Override public boolean safeMethod() { return true; }
}
// PutMethod、DelMethod 僅需實作 getMethod(),沿用預設行為
優點:結構清晰,新增方法只需新增子類別,不動既有代碼。
適用性:物件狀態在生命週期內固定不可變。
若同一個 Method 物件需要在運行期隨時切換 POST/GET/PUT/DELETE,繼承多態就無法滿足(Java 不支援物件動態換類)。此時引入 State 模式:將狀態抽象為介面,每種狀態一個實現類,Context 物件持有對當前狀態物件的引用,並委派行為給它。

public interface MethodType {
String getTypeDescription();
String getMethodDescription();
boolean isSafe();
boolean isRequired();
}
public class Post implements MethodType { /* 實作四個介面方法 */ }
public class Get implements MethodType { /* 實作四個介面方法 */ }
public class Put implements MethodType { /* 實作四個介面方法 */ }
public class Delete implements MethodType { /* 實作四個介面方法 */ }
public class Method {
private MethodType _type;
public Method() { _type = null; }
public Method(MethodType type) { _type = type; }
public String getMethod() { return _type.getMethodDescription(); }
public boolean safeMethod() { return _type.isSafe(); }
public boolean passwordRequired() { return _type.isRequired(); }
// 運行時動態切換狀態
public void changeType(MethodType type) { _type = type; }
public void runAllMethods() {
MethodType[] types = { new Post(), new Get(), new Put(), new Delete() };
for (MethodType t : types) {
System.out.println(t.getTypeDescription());
changeType(t);
System.out.println(getMethod());
System.out.println(safeMethod());
System.out.println(passwordRequired());
}
}
}
優點:狀態切換靈活,符合「組合優於繼承」原則。
適用性:物件需在生命週期中頻繁變更行為。
switch/if,讓系統更易擴展、測試與維護。完整測試代碼請參考原文中的 Client.java,三種實現輸出結果完全一致,驗證了重構的正確性。