第 8 章 下沉複雜性
本章從另一個角度探討如何建立更深的類。假設你正在開發一個新模組,發現有些複雜性不可避免。那麼,是應該讓模組的使用者處理這些複雜性,還是應該在模組內部處理?如果複雜性與模組提供的功能有關,通常應該選擇後者。大多數模組的使用者都比開發人員多,因此讓開發人員多費些力氣,比讓使用者費力更好。作為模組開發人員,你應該儘可能讓模組易於使用,即使這意味著自己要做額外的工作。換句話說,讓模組的介面簡單比讓其實作簡單更為重要。
本章概覽繞不開的複雜性,該由誰來處理?
開發人員很容易反其道而行之:解決簡單的問題,然後將困難的問題推給其他人。如果出現不確定如何處理的情況,最簡單的方法是丟擲例外,讓呼叫者處理。如果不確定要採用什麼策略,就可以定義一些設定參數來控制該策略,然後讓系統管理員自行確定這些參數的最佳值。
這些做法短期內會讓你更輕鬆,但會加劇複雜性,因為原本只需一個人處理的問題,現在許多人都得處理。例如,如果一個類丟擲例外,該類的每個呼叫者都必須處理它。如果一個類暴露了設定參數,每個部署實例的系統管理員都必須學習如何設定這些參數。
8.1 範例:編輯器文字類
考慮 第 6 章 和 第 7 章 中討論過的文字類,它為圖形介面文字編輯器管理檔案中的文字。該類提供了將檔案從磁碟讀入記憶體、查詢和修改檔案在記憶體中的副本,以及將修改後的版本寫回磁碟的方法。學生們在實作這個類時,許多人選擇了行導向的介面,提供讀取、插入和刪除整行文字的方法。這讓類的實作很簡單,但也為更高層級的軟體帶來了複雜性。使用者介面很少執行整行操作。例如,按鍵輸入會在現有行中插入單個字元;複製或刪除所選區域可能修改幾個不同行中的部分內容。使用行導向的文字介面時,更高層級的使用者介面必須自行拆分和連線行。
字元導向的介面(如 第 6.3 節 中所述)下沉了複雜性。使用者介面軟體現在可以插入和刪除任意範圍的文字,而無需拆分和連線行,因此變得更加簡單。不過,文字類的實作很可能會變得更加複雜:如果內部將文字表示為行的集合,就必須拆分和連線行,才能實作字元導向的操作。這種方法更好,因為它將拆分和連線行的複雜性封裝在文字類中,從而降低了系統的整體複雜性。
譯者注(術語說明):原文在此將支援任意字元範圍的介面稱為“字元導向”,而第 11 章用同一名稱表示逐字元操作的介面。兩處操作粒度不同,譯文保留各處原文名稱,請結合相應範例理解。
譯者圖解拆行與合併行應該由誰負責?
8.2 範例:設定參數
設定參數是將複雜性上推而不是下沉的一個範例。類可以不在內部確定具體行為,而是暴露一些參數來控制行為,例如快取的大小,或放棄請求前的重試次數。該類的使用者必須為這些參數指定適當的值。在當今的系統中,設定參數已變得非常流行,有些系統有數百個設定參數。
設定參數的擁護者認為,它們允許使用者根據特定需求和工作負載調整系統。在某些情況下,低層級的基礎結構程式碼很難確定最佳策略,而使用者更加熟悉自己的應用領域。例如,使用者可能知道某些請求比其他請求更緊迫,因此由使用者為這些請求指定更高的優先權是有意義的。在這種情況下,設定參數可以讓系統在更廣泛的應用領域中獲得更好的效能。
但是,暴露設定參數也提供了“偷懶的機會”:迴避重要問題,把它們推給別人。在許多情況下,使用者或管理員很難確定正確的參數值,甚至根本無法確定。在另一些情況下,只要在系統實作中多做一些工作,就可以自動確定正確的值。設想一個必須處理資料包丟失的網路協議。如果它傳送了請求,但在一定時間內未收到響應,就重新發送該請求。確定重試間隔的一種方法是引入設定參數。不過,傳輸協議也可以自行計算一個合理的值:測量成功請求的響應時間,再將這個時間的某個倍數用作重試間隔。這種方法下沉了複雜性,使用者不必自行找出合適的重試間隔。動態計算重試間隔還有一個優點:執行條件變化時,參數值也會自動調整。相比之下,設定參數的值很容易過時。
因此,你應儘可能避免使用設定參數。在暴露設定參數之前,請問自己:“使用者(或更高層級的模組)能確定比我們更好的參數值嗎?” 建立設定參數時,請考慮能否提供合理的預設值,讓使用者只需在特殊情況下指定參數值。理想情況下,每個模組都應徹底解決問題,而設定參數使解決方案不完整,從而增加了系統的複雜性。
譯者圖解重試間隔的知識在哪裡?
8.3 做過頭了
下沉複雜性時要謹慎,因為很容易做過頭。極端的做法是將整個應用程式的所有功能放進一個類,這顯然沒有意義。下沉複雜性在以下情況下最有意義:(a)下沉的複雜性與該類的現有功能密切相關,(b)能簡化應用程式中的其他部分,(c)能簡化類的介面。請記住,目標是最大程度地降低系統的整體複雜性。
第 6 章介紹了學生們如何在文字類中定義一些反映使用者介面的方法,例如實作退格鍵功能的方法。這似乎很好,因為它可以下沉複雜性。但是,將使用者介面的知識新增到文字類中並不會大大簡化高層級的程式碼,並且使用者介面的知識與文字類的核心功能無關。在這種情況下,下沉複雜性只會導致資訊洩露。
譯者圖解下沉文字機制,不下沉按鍵含義
8.4 結論
開發模組時,要尋找機會,自己多費一點力氣,讓使用者少費一些力氣。