核心觀點#

作者 Robert C. Martin 在本章將視角從程式碼細節拉高到「系統架構」層次。
他用「都市」作隱喻:都市能運作,是因有適當抽象層次與模組化,
讓每個人(元件)即便不知整體宏觀目標,也能管好自己的部分。

要設計出整潔系統,關鍵在於將「建造(Construction)」與「使用(Use)」這兩過程分離

  • 建造與使用是截然不同的: 軟體系統應將「啟動過程(建立物件、串聯相依性)」與
    「執行邏輯(實際運作)」劃分開來
  • 分離關注點 (Separation of Concerns): 這是軟體工程最古老也最重要的技巧。
持續保持適當的關注點分離,架構就能隨需求成長,而不需一開始就設計出完美大型架構。

分離建造與使用的策略#

軟體物件被「建造」時,往往伴隨著複雜的相依性串聯。
若將這些邏輯混雜在業務邏輯中,系統會僵化且難測試。以下是幾種常見分離法:

1. 將建造移至 Main (Main Separation)#

將所有物件的建立與串聯責任,全移交給 main 函式(或啟動模組)。

  • 運作方式: main 建立系統所需的一切物件,然後傳遞給應用程式
  • 結果: 應用程式對「建造過程」一無所知,它只預期所有物件都已準備好,可直接使用

Figure 11.1: Separating construction in main()

2. 工廠模式 (Abstract Factory)#

有時應用程式需決定「何時」建立物件,但我們仍不希望它知道「如何」建立。

  • 運作方式: 應用程式呼叫一個介面(Abstract Factory)來生產物件
  • 結果: 具體建立細節(實作類別)被隔離在工廠實作中,應用程式只依賴抽象介面

Figure 11.2: Separation construction with factory

3. 相依性注入 (Dependency Injection, DI)#

這是分離建造與使用最強大的機制,符合控制反轉 (Inversion of Control, IoC) 原則。

  • 概念: 物件本身不負責實體化它的相依性(Dependency),
    而是將責任交給另個權威機制(如 main 或 DI 容器)
  • 實作: 物件僅透過建構子(Constructor)或 Setter 來接收它需要的資源
  • 例子: Spring Framework 是 Java 領域中最著名的 DI 容器實作

Figure 11.3: The 'Russian doll' of decorators


擴展系統:模組化與 AOP#

軟體系統不同於物理建築,它具有高度動態性。 我們不需「一開始就做對(Big Design Up Front)」,只要將關注點分離得當,架構是可以隨著需求演進。

橫切關注點 (Cross-Cutting Concerns)#

系統中,有些功能(如日誌記錄、安全性檢查、交易管理)會散落在各物件中。
這些邏輯雖然重要,但與核心業務邏輯無關,且會導致程式碼重複與混亂。

剖面導向程式設計 (AOP)#

Aspect-Oriented Programming (AOP) 是種將這些「橫切關注點」模組化的技術。

  • 目的: 建立「剖面(Aspect)」,定義系統中哪些行為需被統一處理
  • 優點: 可將非核心的基礎設施邏輯從業務物件中抽離,讓業務邏輯純粹
POJO 與架構的敏捷性

POJO (Plain Old Java Objects): 指那些沒有繼承複雜框架、僅包含單純業務邏輯的物件。

整潔系統的理想樣貌: 用 POJO 撰寫核心領域邏輯,
並用 AOP 以「非侵入」方式將橫切關注點(如 Persistence, Logging)組合進來。

這樣的架構能讓設計意圖清晰可見,並賦予團隊極大敏捷性——
你可在最後一刻才決定具體的基礎設施細節。


結論#

一個良好的系統設計,其 API 多數時候應「消失」在視線範圍內。這讓團隊能專注於使用者故事(User Stories)的實作,而不是被框架的繁文縟節所困擾。

  • 適當抽象化: 讓各層次模組化
  • 延遲決策: 具備模組化關注點的系統,允許開發者用最新知識在最後一刻做最佳決策

“Software systems are unique compared to physical buildings.
Their architectures can grow incrementally, if we maintain the proper separation of concerns.” 軟體系統與實體建築不同。只要我們維持適當的關注點分離,軟體架構是可以遞增成長的。