首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 物件導向設計 61 條鐵律:從封裝到繼承的完整指南

     編輯:PHP 相關知識

前言:這不是教條,是警鐘

Arthur J. Riel 在《物件導向設計啟示錄》中提出的 61 條啟發式規則,並非要你教條遵守,「違背也不會被處以宗教刑罰」。但請將它們視為設計警鐘:一旦違背,警鐘響起,提醒你審視當下的決策是否合理。以下將這 61 條原則歸類整理,並輔以現代 PHP 開發視角的註解,助你構建高內聚、低耦合、可演進的系統。

一、核心封裝與接口原則(1-6)

1. 數據全隱藏

所有數據成員必須 private。拒絕 public 屬性,甚至 protected 也要慎用。PHP 8.1+ 的 readonly 屬性配合建構子,是實現此原則的利器。

2. 使用者依賴接口,類不依賴使用者

定義清晰的 public 方法作為契約。類內部實現細節變更不應影響呼叫端。這是「面向介面編程」的基石。

3. 極小化協議(接口)

類的公共方法越少越好。每個方法都是潛在的耦合點。接口隔離原則 (ISP) 的直接體現。

4. 實現通用基礎接口

所有類應支援:深/淺拷貝(__clone)、相等比較、序列化輸出、從標準格式(JSON/陣列)解構。PHP 的 JsonSerializable、__serialize/__unserialize 機制正是為此而生。

5. 實現細節不入公共接口

共用邏輯抽取為 private 方法,而非 public。protected 僅供繼承體系內部複用。

6. 接口不污染

不要暴露使用者「用不上」或「不關心」的方法(如內部初始化、緩存清理等)。

二、類之間的關係與耦合(7-15)

7. 零耦合或導出耦合

類之間要么無關,要么僅通過 public 接口交互。嚴禁直接訪問對方 private/protected 成員(反射除外,且慎用)。

8. 單一關鍵抽象 & 共同封閉原則 (CCP)

一個類只代表一個核心概念。同一包內的類應對同類變化共同封閉:若變化波及一個類,通常波及包內所有類,但不影響其他包。這是模組化設計的指引。

9. 數據行為共置

發現「頻繁透過 getter 從別的對象取數據再操作」?違反了此原則。行為應搬到數據所在的類。Tell, Don't Ask。

10. 無關信息分離 & 依賴穩定方向

互不溝通的行為拆分到不同類。依賴應指向穩定、抽象的方向(介面、抽象類),而非具體實現。

11. 建模的是類,而非角色

「用戶」是角色,「賬戶」、「個人資料」、「權限策略」才是類。不要把角色當類建模。

12. 功能水平均勻分布

頂層類應協作分擔職責,避免「上帝類」包辦一切。

13. 拒絕全能類

名稱含 Manager、Handler、Service、System、Util、Helper 的類極易腐化為全能類。規劃接口,而非實現接口。

14. 警惕大量存取器

滿屏 getXxx/setXxx 通常意味著「貧血模型」:數據與行為分離。重構機會來了。

15. 警惕互不相關的行為堆砌

類內方法互不呼叫、操作不同屬性組?拆分之。

三、模型與視圖、現實建模(16-17)

16. 模型不依賴視圖,視圖依賴模型

經典 MVC 依賴規則。PHP 模板引擎(Twig、Blade)只應讀取模型數據,模型零依賴視圖。

17. 儘量貼近現實世界建模

但為了遵守上述原則(如避免全能類、功能均勻分布),有時必須偏離純現實映射。設計服務於原則,原則服務於可維護性。

四、類的純淨度與層級(18-21)

18. 移除多餘類 → 降級為屬性

若類無行為、僅攜帶數據,它應是值對象或嵌入屬性,而非獨立實體。

19. 移除系統外部類

只向系統發消息、不接收消息的類,屬於外部整合層(如 API Client),不應混入核心域模型。

20. 操作別變成類

動詞命名、單一方法的類(如 CalculateTotal)通常應遷移至相關領域類為方法。名詞建模,動詞賦能。

21. 清理無用代理類

分析階段引入的代理,設計階段若無實際委派職責,果斷刪除。

五、協作與扇出控制(22-28)

22-25. 極小化:協作者數量、消息數量、協作種類、扇出度

扇出 = 定義的消息數 × 發送的消息數。高扇出意味著類過於複雜、難測試、難復用。拆分職責、引入中介者、使用領域事件解耦。

26. 包含即使用

組合關係意味著外層類會調用內層對象方法。別持有不用的對象。

27. 方法用數據

大多數方法應使用大多數屬性。若某方法只用一兩個屬性,考慮提取為獨立類(內聚性檢驗)。

28. 類內對象數 ≤ 7(短期記憶極限)

超過 6 個屬性/協作者,將邏輯相關者分組,封裝為新的值對象或聚合根。

六、繼承體系設計(29-57)

29-30. 窄而深的繼承 & 語義約束下沉

功能在繼承層次中垂直分布。約束優先在類定義(型別系統)實現;若導致類爆炸,則在建構子/行為中驗證。

31. 約束測試盡可能深

建構子驗證時,將檢查下沉到最具體的子類層級,避免基類建構子過於膨脹。

32-33. 約束信息變化頻率決定存放位置

常變 → 集中式第三方對象(策略模式);少變 → 分散在相關類中。

34. 知子不知父

類知道自己包含什麼(組合),但不應知道誰包含自己(無反向導航)。

35. 同作用域對象互不使用

同一個類包含的多個屬性對象之間,不應直接調用。協作由宿主類統籌。

36. 繼承專用於「特化」

IS-A 關係。代碼復用請用組合/委派,別濫用繼承。

37. 子知父,父不知子

單向依賴。基類零耦合具體子類,支援開放封閉原則 (OCP)。

38. 基類數據全私有,拒絕 protected

繼承破壞封裝。子類需要數據?提供 protected 存取器方法,而非暴露欄位。

39-40. 理論深、實踐淺(≤6層)

繼承鏈深度不超過人腦短期記憶極限(6)。過深必重構。

41-42. 抽象類即基類,基類即抽象類

具體類不應被繼承。final 是好朋友。

43. 共性上移

數據、行為、接口的共同點盡量推到繼承鏈高端。但警惕「拒絕繼承」(子類不需要父類某功能) —— 違反里氏替換原則 (LSP) 的信號。

44. 共享數據無共享行為 → 組合

提取為獨立類,各類包含它。而非繼承。

45. 共享數據且共享行為 → 繼承

提取公共基類。經典模板方法模式適用場景。

46. 共享接口(多態需求)才繼承

若只共享方法簽名但無多態調用,用介面 + 組合,別用繼承。

47. 顯式類型分支 → 多態

if ($obj instanceof A) ... elseif ($obj instanceof B) ... 是設計失敗的氣味。引入共同介面,實現多態分發。

48. 顯式屬性值分支 → 繼承層次

if ($user->type === 'admin') ... → AdminUser 繼承 User。屬性值變類型。

49. 別用靜態繼承建模動態語義

運行時切換類型(如訂單狀態:新建→付款→發貨)用狀態模式(組合),別用繼承。

50. 單實例子類 = 設計錯誤

若某子類在系統中永遠只有一個實例,它本質是對象,不是類。內聯回父類或用單例模式(慎用)。

51. 運行時創建類?退回建模對象

動態生成類通常意味著你需要的是「對象實例」的動態屬性/行為,而非新類型。用數據驅動設計。

52. 空方法覆寫 = 非法

子類為滿足介面而實現空方法,違反 LSP。介面拆細、或用空對象模式。

53. 可選包含 ≠ 繼承

「可選擁有某功能」用組合/策略模式。強行繼承會導致類爆炸。

54. 建可復用框架,非可復用組件

框架定義骨架與擴展點(Template Method、Hook),組件只是葉子節點。框架才能真正復用架構。

55. 多重繼承:先假設你錯了

PHP 不支援多重繼承(僅 trait),但介面可多實現。若真需多繼承,先證明組合/介面無法解決。

56. 繼承自檢兩問

  1. 子類是否父類的一種特殊類型?(IS-A)
  2. 父類是否子類的一部分?(HAS-A 的反面,防止反向繼承)

57. 鑽石繼承檢查

多介面實現時,確保無基類實際是另一基類的子類(避免隱式鑽石問題)。

七、包含 vs 關聯、全域狀態、物理與邏輯(58-61)

58. 選包含,不選關聯

包含(組合)語義更強、生命週期綁定更緊密、封裝性更好。關聯鬆散,慎用。

59. 拒絕全域變量/函數做備忘錄

用 static 類屬性/方法、或單例服務(如 Cache::get())。全域狀態是測試與並發的大敵。

60. 物理設計不破壞邏輯設計

目錄結構、命名空間、文件分割服務於邏輯架構,而非主導它。但物理約束(如部署單元、團隊邊界)可作為邏輯決策參考輸入。

61. 不繞過公共接口修改狀態

反射、屬性掛鉤、直接 $obj->prop = ...(若非 private)均屬違規。狀態變更必須經過領域方法,保證不變量。

結語:原則是地圖,代碼是領土

這 61 條規則不是死板清單,而是設計嗅覺的訓練手冊。將它們內化為直覺,你在寫下每一行 class、每一個 public function 時,腦海中就會自動掃描潛在違規。PHP 現代特性(型別系統、readonly、屬性掛鉤、enum、trait)給了我們更強工具去踐行這些原則。下次重構時,不妨帶著這份清單做一次「設計體檢」—— 你會驚訝於發現的隱患之多,也會慶幸於修復後架構的清爽。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved