多態是物件導向設計實現開放封閉原則(對擴展開放,對修改封閉)的核心手段。本文透過主板 PCI 插槽與資料庫存取切換兩大經典案例,展示多態如何消除重複代碼、支援未來功能無縫擴展。
問題背景:主板需啟動網卡、聲卡等模組。若主板直接 `new NetCard()`、`new SoundCard()`,新增模組需修改主板代碼,違反開放封閉原則。
多態解決方案:定義 `PCI` 介面,主板依賴抽象而非具體實作。
interface PCI { void open(); void close(); }
class MainBoard {
public void run() { System.out.println("mainboard run"); }
// 依賴介面,而非具體類
public void usePCI(PCI p) {
if (p != null) { p.open(); p.close(); }
}
}
class NetCard implements PCI { /* 實作 open/close */ }
class SoundCard implements PCI { /* 實作 open/close */ }
// 客戶端代碼
MainBoard mb = new MainBoard();
mb.run();
mb.usePCI(new NetCard()); // 新增模組零修改 MainBoard
mb.usePCI(new SoundCard());
mb.usePCI(new UsbCard()); // 未來擴展:只需實作 PCI 介面
核心優勢:主板與具體模組解耦,新增模組只需實作 `PCI` 介面,主板代碼零修改。
問題背景:系統需支援 JDBC 與 Hibernate 兩種持久化方式,核心操作(連線、增刪改查、關閉)高度相似。
多態解決方案:定義 `UserInfoDao` 介面封裝共同契約。
interface UserInfoDao {
void add(User user);
void delete(User user);
}
class UserInfoByJDBC implements UserInfoDao {
public void add(User u) { /* 1.JDBC連線 2.SQL插入 3.關閉 */ }
public void delete(User u) { /* 1.JDBC連線 2.SQL刪除 3.關閉 */ }
}
class UserInfoByHibernate implements UserInfoDao {
public void add(User u) { /* 1.Hibernate連線 2.保存 3.關閉 */ }
public void delete(User u) { /* 1.Hibernate連線 2.刪除 3.關閉 */ }
}
// 客戶端:只需替換實作類,業務邏輯零修改
UserInfoDao dao = new UserInfoByHibernate(); // 或 new UserInfoByJDBC()
dao.add(user);
dao.delete(user);
| 維度 | 介面 | 抽象類 |
|---|---|---|
| 多重實作 | 支援多介面實作(模擬多重繼承) | 單一繼承 |
| 預設實作 | JDK8+ default 方法 | 可提供完整/部分實作 |
| 演進成本 | 修改介面影響所有實作(慎用) | 新增非抽象方法不影響子類 |
| 適用場景 | 定義契約/能力(如 Serializable、PCI) | 定義骨架/共享邏輯(如 Template Method) |
建議:優先用介面定義對外契約,抽象類用於內部共享邏輯;兩者結合(介面 + 抽象骨架類)最靈活。
深刻理解並善用多態,是從「寫出功能代碼」進階到「設計可演進架構」的關鍵分水嶺。