面向對象設計的核心價值在於「應對變化」。本文透過打印機案例,展示如何從「複製貼上修修補補」演進至「繼承多態優雅擴展」,體現 OOP 核心思想。
class HPPrinter {
void open() { System.out.println("Open"); }
void print(String s) { System.out.println("print-->" + s); }
void close() { System.out.println("Close"); }
}
class Test {
public static void main(String[] args) {
HPPrinter hp = new HPPrinter();
hp.open(); hp.print("abc"); hp.close();
}
}
問題:新增品牌需複製整個類別、修改主程式邏輯,違反開閉原則。
class CanonPrinter {
void open() { System.out.println("Open"); }
void print(String s) { System.out.println("print-->" + s); }
void close() { this.clean(); System.out.println("Close"); } // 差異點
void clean() { System.out.println("Clean"); }
}
class Test {
public static void main(String[] args) {
int brand = 0; // 0=Canon, 1=HP
HPPrinter hp = new HPPrinter();
CanonPrinter canon = new CanonPrinter();
if (brand == 1) { hp.open(); hp.print("abc"); hp.close(); }
else { canon.open(); canon.print("123"); canon.close(); }
}
}
問題:每新增品牌,主程式就要新增 if-else 分支,維護災難。
// 父類別:封裝共同行為
class Printer {
void open() { System.out.println("Open"); }
void print(String s) { System.out.println("Print-->" + s); }
void close() { System.out.println("Close"); }
}
// 子類別:繼承共同行為,覆寫差異行為
class HPPrinter extends Printer {
// 完全復用父類別,無需任何代碼
}
class CanonPrinter extends Printer {
@Override
void close() {
this.clean(); // 子類別特有邏輯
super.close(); // 呼叫父類別通用邏輯
}
void clean() { System.out.println("Clean"); }
}
class Test {
public static void main(String[] args) {
int brand = 0;
Printer printer; // 宣告父類別型別
if (brand == 1) printer = new HPPrinter();
else printer = new CanonPrinter();
// 統一介面呼叫,具體行為由實際物件決定
printer.open();
printer.print(brand == 1 ? "abc" : "123");
printer.close();
}
}
| 階段 | 設計 | 新增品牌成本 | 主程式耦合度 | 核心原則 |
|---|---|---|---|---|
| 一 | 單一類別 | 複製整類 | 強耦合具體類 | — |
| 二 | 多類別+if-else | 新類+改主程式 | 強耦合具體類 | — |
| 三 | 繼承體系 | 新子類別 | 依賴父類別 | 開閉原則 |
| 四 | 多態調用 | 新子類別 | 面向介面/父類 | 里氏替換/依賴倒置 |
Printer p = new CanonPrinter(); 隱藏具體型別,暴露統一介面class PrinterFactory {
public static Printer createPrinter(int brand) {
switch (brand) {
case 1: return new HPPrinter();
case 0: return new CanonPrinter();
default: throw new IllegalArgumentException("Unknown brand");
}
}
}
// 主程式完全無條件判斷
Printer printer = PrinterFactory.createPrinter(brand);
printer.open(); printer.print(...); printer.close();
從「複製代碼」到「繼承多態」,再到「工廠封裝建立」,這條重構之路完美詮釋了面向對象設計精髓:
這不只是語法練習,更是構建可維護、可擴展系統的思維訓練。下次面對「類似但不完全相同」的需求時,請先思考:什麼是共同的?什麼是不同的?如何用繼承與多態優雅表達?