在軟體開發中,總有一些部分特別難測試(例如 GUI 畫面、資料庫整合)。
為讓這些部分也能被納入測試覆蓋範圍,Uncle Bob 介紹了一個強大設計模式:謙卑物件模式(The Humble Object Pattern)

一、謙卑物件模式#

這模式的核心思想: 將原本難測試的行為拆解成兩個模組(類別)。

  1. 謙卑模組 (The Humble Module):
    • 包含所有難測試的行為(如直接操作 DOM、繪製像素)
    • 邏輯非常簡單、甚至近乎愚蠢(Dumb),以至於不需測試(因為太簡單了,幾乎不可能寫錯)
    • 因它什麼都不懂,所以很「謙卑」
  2. 邏輯模組 (The Logic Module):
    • 包含所有與該行為相關的邏輯
    • 完全不依賴 GUI 或 DB
    • 易於測試

二、經典案例:Presenters 與 Views#

這是謙卑物件模式最常見的應用,發生在 UI 邊界上。

1. View (謙卑物件)#

  • 角色: 它是 GUI 的外殼
  • 職責: 只負責將數據載入螢幕。它不應做任何決策(例如:不該決定「因為餘額是負的所以顯示紅色」,只該負責「顯示紅色」)
  • 測試: 難以測試,但因邏輯已被剝離,所以不需要測試

2. Presenter (邏輯模組)#

  • 角色: 它是 View 的大腦
  • 職責: 接受來自應用程式的資料,並將其格式化為 View 可直接使用的形式
    • Date 物件轉換成字串 "2023-10-27"
    • Money 物件轉換成字串 "$100.00"
    • 決定布林旗標(如 isRedText = true
  • 測試: 非常容易測試,因它只是在操作單純的資料結構

3. View Model#

Presenter 與 View 間傳遞的是一個單純的資料結構,稱為 View Model

  • 它只包含字串、布林值和列舉(Enums)
  • View 只是盲目地讀取 View Model 中的欄位並顯示出來
flowchart LR
    subgraph 邏輯模組["邏輯模組 (易於測試)"]
        P[Presenter]
    end
    subgraph 謙卑物件["謙卑物件 (難以測試)"]
        V[View]
    end

    App[應用程式資料] --> P
    P -->|格式化| VM[View Model<br/>字串/布林值]
    VM --> V
    V -->|顯示| Screen[螢幕]
    style P fill: #d4edda, stroke: #155724
    style V fill: #f8d7da, stroke: #721c24
    style VM fill: #fff3cd, stroke: #856404

三、其他應用:資料庫閘道器#

這模式不僅用於 UI,也用於資料庫邊界。

  • SQL 是謙卑的: SQL 語句本身難以測試(需要連線 DB)
  • Interactor 是邏輯的: 業務邏輯不該包含 SQL
  • Gateway (謙卑物件): 介面轉接層中的 Gateway 負責執行 SQL。
    這部分被視為謙卑物件,實作簡單的 CRUD,而複雜的查詢邏輯則盡量移至可測試的 Interactor 中

謙卑物件模式是「架構邊界」的守護者。 透過將難測試的「介面」與易測試的「邏輯」分離,我們能大幅提升系統的可測試性,
確保業務邏輯(Presenter/Interactor)即便在沒有 UI 或 DB 的情況下也能被完整驗證。