什麼是 SOLID?與 OOP 的根源
許多工程師都有過類似的經驗:接手一份「能跑就好」的舊專案,或只是想改一個小功能,卻發現牽一髮動全身,改了 A 壞了 B,修了 B 又壞了 C;幾輪下來,程式碼愈來愈難以理解,沒有人敢輕易動它。 這種現象有個名字,叫做程式碼腐化(Software Rot);它的成因不是因為工程師不夠努力,也不是因為程式語言本身的限制,而是因為程式碼在設計上缺乏清晰的邊界與結構,隨著時間累積,複雜度像滾雪球一樣不斷擴大。 程式碼腐化常見的三種症狀: Fragility(脆弱性):系統在意想不到的地方發生錯誤;改了一處邏輯之後,看似無關的另一個模組卻開始出錯,原因是它們之間存在隱藏的耦合。 Rigidity(僵化性):每一個改動都需要修改大量的地方,工程師必須追蹤一長串的連鎖反應,導致任何變更的成本都極高。 Immobility(不動性):某段邏輯明明可以在其他地方複用,卻因為它與太多其他元件糾纏在一起,根本無法單獨抽出來。 SOLID 就是為了系統性地對抗這三種症狀而誕生的。 SOLID 的由來 Robert C. Martin(人稱 Uncle Bob)是《Clean Code》與《Clean Architecture》的作者,也是敏捷宣言的共同簽署人之一,他在 2000 年代初期,將多年在軟體工程領域的觀察與實踐整理成文,提出了五個核心設計原則。 這五個原則各自在過去幾十年間分散出現於不同的學術論文與工程討論中,Uncle Bob 的貢獻在於將它們系統化,並賦予一致的框架;之後 Michael Feathers(《Working Effectively with Legacy Code》的作者)發現這五個原則的英文首字母恰好組成「SOLID」,這個縮寫從此沿用至今。 五個原則各自對應的英文全名與中文名稱: S — Single-Responsibility Principle:單一職責原則 O — Open-Closed Principle:開放封閉原則 L — Liskov Substitution Principle:里氏替換原則 I — Interface Segregation Principle:介面隔離原則 D — Dependency Inversion Principle:依賴反轉原則 OOP 的四個基石,以及它們的局限 物件導向程式設計(OOP)提供了四個強大的工具: 封裝(Encapsulation):將資料與操作資料的方法包裝在一起,隱藏實作細節,只對外暴露必要的介面;這讓模組之間的邊界更清楚,也保護了資料不被任意存取。 繼承(Inheritance):讓子類別繼承父類別的屬性與行為,實現程式碼的複用;它也建立了「is-a」的型別關係,讓一個子類別的物件可以被當作父類別使用。 多型(Polymorphism):同一個介面或方法名稱,可以在不同的類別中有不同的實作;呼叫端只需要知道「這個物件能做什麼」,不需要知道「它是怎麼做的」,讓程式碼更具彈性。 抽象(Abstraction):透過介面(Interface)或抽象類別(Abstract Class),只定義行為的「輪廓」,而不指定實作,這讓高階的業務邏輯可以與低階的實作細節解耦。 然而這四個工具只是手段,本身並不保證良好的設計;一個大量使用繼承、卻讓子類別行為不一致的系統,可能比不用繼承更糟糕;一個把所有邏輯封裝在同一個「萬能類別」裡的設計,只是用封装帶來更大的隱患;OOP 告訴你可以做什麼,SOLID 告訴你應該怎麼做。 ...