核心設計原則分類
一、封裝與接口設計 (1-6)
- 數據隱藏:所有數據私有,通過公共接口訪問
- 依賴接口:使用者依賴公共接口,類不依賴使用者
- 最小接口:減少公共協議中的消息數量
- 標準協議:實現拷貝、相等、輸出、解析等通用操作
- 實現細節私有化:公共代碼提取為 private 方法,不暴露接口
- 接口純粹性:不以用戶無法使用/不關心的內容污染接口
二、耦合與內聚 (7-10)
- 零耦合或導出耦合:類間無關或僅使用公共接口
- 單一職責:類只表示一個關鍵抽象
- 封閉共同變化:包內類對同類變化共同封閉
- 相關數據行為集中:發現通過 getter 獲取數據再操作的「特性依賴」,應合併
三、職責劃分與避免上帝類 (11-20)
- 不相關信息分離:互不溝通的行為分離到不同類
- 依賴穩定方向:依賴抽象/穩定接口,不依賴具體/易變實現
- 建模類而非角色:確保抽象是類,非對象臨時扮演的角色
- 功能水平分布:頂層類均勻分擔工作
- 拒絕全能類:警惕
Manager/Controller/Service/System/Helper 命名
- 規劃接口而非實現:面向接口編程
- 警惕大量存取器:暗示數據行為未集中
- 警惕互不相關行為:大量無關方法違反內聚
- 模型不依賴視圖:UI 依賴模型,模型不知 UI
- 儘量貼近現實建模:但為遵循上述原則可適度偏離
四、類純化與層次 (18-21)
- 移除無用類:降級為屬性
- 移除系統外類:僅發送消息不接收的類
- 操作不變類:動詞命名、單一行為的類應併入相關類
- 清理無用代理:設計階段移除分析階段引入的無效代理
五、協作最小化 (22-25)
- 最少協作者:類使用的其他類數量最小化
- 最少消息:協作間傳遞消息數最小化
- 最少協作類型:不同消息類型最小化
- 最小扇出:定義消息數 × 發送消息數 最小化
六、包含與使用關系 (26)
- 包含即使用:包含類必須向被包含對象發送消息
七、類內部結構 (27-28)
- 方法用數據:大多數方法使用大多數數據成員
- 成員數量 ≤ 7±2:超過拆分為包含類
八、繼承體系設計 (29-43)
- 窄深繼承:功能在窄深層次垂直分布
- 語義約束下沉:盡量在類定義/構造函數深處實現約束
- 約束信息變化策略:常變→集中式第三方對象;少變→分布在相關類
- 知子不知父:子類知基類,基類不知子類
- 基類數據私有:嚴禁 protected 數據
- 接口最小化:不將使用者不需要的放入公共接口
- 理論深度無限,實踐 ≤ 6:受限於短期記憶
- 抽象類即基類:所有抽象類應為基類
- 基類必須抽象:所有基類應為抽象類
- 共性上移:數據/行為/接口共性盡可能上移繼承層次
- 共享數據→包含:共享數據無共享行為時,包含公共數據類
- 共享數據行為→繼承:共享數據和方法時,繼承公共基類
- 共享接口→多態:需多態使用時才繼承公共基類
九、多態與類型判斷 (47-48)
- 拒絕顯式類型判斷:
if ($obj instanceof A) → 多態
- 屬性值判斷→繼承:將屬性值轉為派生類
十、繼承濫用防範 (49-57)
- 繼承不建模動態語義:靜態關系無法表達運行時類型切換
- 對象不變類:單實例派生類即可疑
- 運行時建類→建對象:需動態創建類時,退回建對象+概括為類
- 禁用空覆寫:子類空方法覆寫父類應非法
- 可選包含≠繼承:將可選包含建模為繼承導致類爆炸
- 框架而非組件:創建可復用框架,非可復用組件
- 多重繼承默認錯誤:使用前先假設錯誤,需證明必要性
- 繼承自問:(1) 子類是父類特殊類型?(2) 父類是子類一部分?
- 菱形檢查:多重繼承中無基類是另一基類派生
十一、關系選擇與全局狀態 (58-61)
- 包含優於關聯:優先選擇包含關系
- 類變量/方法替代全局:不用全局數據/函數做簿記
- 邏輯設計優於物理:不讓物理約束破壞邏輯,但決策時參考物理
- 不繞過接口改狀態:嚴禁
$obj->privateProp = ... (反射除外)
實戰檢查清單 (Code Review 時逐項核對)
| 類別 | 檢查點 | 違規示例 | 修正方向 |
| 封裝 | public 屬性 | public $name; | private + getter/setter |
| 接口 | 方法超過 10 個 | Service 類 30+ 方法 | 拆分接口/類 |
| 耦合 | 構造函數注入 5+ 依賴 | new A(new B(new C...)) | Facade/容器/重構 |
| 繼承 | 深度 > 4 | Base → User → Member → VIP → SVIP | 組合/策略模式 |
| 多態 | if ($type === 'A') | 控制器中大量類型判斷 | 工廠+多態 |
| 上帝類 | 類名含 Manager/Service/Helper | UserManager 500 行 | 按領域拆分 |
| 全局狀態 | 靜態單例/全局變量 | $GLOBALS['db'] | 依賴注入容器 |
現代 PHP 落地建議
- 嚴格類型:
declare(strict_types=1) + 類型聲明
- 最終類:
final class 防止意外繼承
- 只讀屬性:PHP 8.1+
readonly 替代 getter-only
- 屬性鉤子:PHP 8.4+
hook 統一訪問控制
- 依賴注入容器:PHP-DI / Symfony DI / Laravel Container 管理對象圖
- 靜態分析:PHPStan Level 5+ / Psalm 強制檢查上述原則
- 架構測試:PHPArch / Deptrac 驗證層級依賴規則
總結
這 61 條軍規源自 Arthur Riel《面向對象設計啟示錄》,經過 PHP 語境適配。核心精神:**高內聚、低耦合、依賴倒置、接口隔離、單一職責**。現代 PHP 配合嚴格類型、靜態分析、容器化部署,能在語言層面強制落地大部分原則。代碼審查時攜帶檢查清單,將設計原則轉化為可執行的工程規範。