介面是 Java 面向對象設計的基石,不僅是方法簽名的集合,更是「契約」、「規範」與「擴展點」的載體。本文從雙重間諜安全隔離、標準化組織適配、多態分派三個生動場景,深度闡述介面的核心價值與最佳實踐。
// 單類實現多介面方法,調用者可見所有方法
class DoubleAgent {
public String speak() { return "Hello"; } // 英語
public String sprechen() { return "Gutentag"; } // 德語
}
// MI5 拿到 DoubleAgent 實例,能調用 sprechen()!洩露機密
DoubleAgent agent = new DoubleAgent();
agent.speak(); // 正常
agent.sprechen(); // ❌ 安全漏洞:不應暴露給 MI5
interface BritishSpy { String speak(); }
interface GermanSpy { String sprechen(); }
class DoubleAgent implements BritishSpy, GermanSpy {
public String speak() { return "Hello"; }
public String sprechen() { return "Gutentag"; }
}
class Agency {
// 僅接受 BritishSpy,不可見 GermanSpy 方法
static void toMI5(BritishSpy spy) { spy.speak(); }
// 僅接受 GermanSpy
static void inGermany(GermanSpy spy) { spy.sprechen(); }
public static void main(String[] args) {
DoubleAgent da = new DoubleAgent();
toMI5(da); // 安全:僅暴露 speak()
inGermany(da); // 安全:僅暴露 sprechen()
// toMI5((GermanSpy)da); // 編譯錯誤:類型不匹配
}
}
核心價值:介面作為「視野邊界」,調用者僅見契約定義的方法,實現細節、其他能力完全屏蔽。
// 歷經 N 代演進的巨無霸類,被無數客戶依賴
class LegacySystem extends BaseA /* extends BaseB ... */ {
public void init() { /* 複雜邏輯 */ }
public void release() { /* 複雜邏輯 */ }
public String doXXX() { return "XXX"; }
public String doYYY() { return "YYY"; }
// 無法修改 doXXX/doYYY 簽名,否則破壞所有客戶
}
// 標準化組織定義契約
interface IBusiness {
String getXXX();
String getYYY();
}
// 僅在類聲明處添加 implements,委派實現
class LegacySystem extends BaseA implements IBusiness {
// 既有方法完全不變
public void init() { /* ... */ }
public String doXXX() { return "XXX"; }
// 新增介面方法,委派既有邏輯
public String getXXX() { return doXXX(); }
public String getYYY() { return doYYY(); }
}
雙贏:舊客戶繼續用 LegacySystem 引用調用 doXXX();新客戶用 IBusiness 引用調用 getXXX()。零破壞、零重寫。
interface Fight { void fight(); }
class FatFat implements Fight {
public void fight() { System.out.println("FatFat 打人很痛!"); }
}
class ThinThin implements Fight {
public void fight() { System.out.println("ThinThin 打人一點都不痛!"); }
}
// 客戶端代碼:完全不知具体實現類
public class Game {
public void battle(Fight fighter) { // 依賴抽象
fighter.fight(); // 動態分派:FatFat/ThinThin 不同行為
}
public static void main(String[] args) {
Game game = new Game();
game.battle(new FatFat()); // 輸出:FatFat 打人很痛!
game.battle(new ThinThin()); // 輸出:ThinThin 打人一點都不痛!
}
}
若無介面,battle 需接受具體類,每新增角色必須修改簽名,違反開閉原則。
Comparable、Runnable)IBusinessV2) 或默認方法-able (Runnable, Serializable) 或名詞 Listener, Repositoryinterface Constants { int MAX = 100; } 反模式,用 enum 或工具類@FunctionalInterface,支援 Lambda (JDK 8+)| 場景 | 選擇 | 理由 |
|---|---|---|
| 跨體系通用能力 | 介面 | 多實現、無狀態共享 |
| 共享代碼/狀態模板 | 抽象類 | 模板方法、字段複用 |
| API 公開給第三方 | 介面 | 隱藏實現、便於 Mock/代理 |
| 內部框架基類 | 抽象類 | 演進成本低、可加默認實現 |