重點整理:
- 用細緻的方式回到基本去討論依賴注入(Dependency Injection)
- 測試系統時需要實例化物件,實例化物件時常放了很多測試替身(Test-double)進去,讓測試更困難
- 類別的靜態變數有時牽涉到單例(Singleton)設計模式,要一起實例化,讓測試更麻煩
- 實例化很困難意味著難以測試
- 超文本文件類別為例,文件只在乎客戶端產生的文件,不需要瞭解客戶端如何產生文件
- 車類別為例,車只在乎產生的引擎,不需要了解引擎怎麼產生
- 違反得墨忒耳定律(Law of Demeter a.k.a. LoD,簡單說即只拿直接需要的物件)
- 將服務定位器傳給要實例化的物件,看建構子參數不夠,還得追建構子程式碼才知道相依的物件,這會隱藏物件間真正的相依性
- 以房子類別為例,實例化房子卻傳入整個家的狀態,追建構子才知只要門、窗與屋頂
- 給房子還要給整個家的物件,導致物件重用性變差
- 解決方式是不透過定位器,明確將門、窗與屋頂作為參數傳給房子
- 此舉能讓獨立測試變得容易
- 服務定位器把查詢與建立物件的功能混淆
- 還需要額外的介面、覆寫或仿造服務定位器的設定方法(setter)
- 以致一旦依賴服務定位器,也需要依賴其他跟服務定位器有關的東西
- 服務定位器有很多別名,本質上都是只需要部分物件但給了全世界
- 以結帳為例,一般來說只會拿錢(直接需要的物件)給店員(請求物件的物件),不會整個錢包(全域狀態)給店員
- 只請求直接需要的物件
- a.getX().getY()亦即間接取得物件即違反得墨忒耳定律
- 好萊塢法則(Hollywood principle, that is "Don't call us, we'll call you")
- 子物件新增一個參數,則父物件要一路傳遞參數直到給子物件
- 事實上父物件並不負責建構子物件,父物件並不知道子物件怎麼建構的,所以也沒有傳遞參數的問題
- 房子類別為例,房子並不知道門有門把,房子只需要建構好的門物件
- 工廠模式(Factory pattern)負責將物件組合起來,與業務邏輯分開
- 同一個生命週期的類別們只要同一個工廠組合就夠,並不用一個類別一間工廠,所以不會導致類別倍數增生
- 注入的物件生命週期應該大於等於被注入的物件,如果有生命週期較短的物件,應該調整架構,將短生命週期的物件分群
- 到處是空指標檢查讓測試變得困難
- 測試房子的油漆功能不需要門,傳入門的空指標,但門的空指標檢查讓測試無法繼續
- 與其到處用先決條件檢查,不如用許多測試確保程式能跑
- 如果物件是給外部使用的應用程式介面(API),加入先決條件檢查是合理的
- 但若給內部使用,一堆先決條件檢查表示對程式的穩定性沒有信心
- 產品程式碼不應該傳空指標給物件,應該用空集合代替,若希望傳入的集合做事就實作方法,不然就給無操作(NOP a.k.a. NOOP)
- 測試程式碼可以傳空指標給物件,目的在表明此物件與測試無關
- 產品程式碼不應該在工廠類別外的類別呼叫new運算元,即業務與建構邏輯混淆
- 測試程式碼為了實例化小部分的程式做測試可以呼叫new運算元
- 絕大部分的情況應該避免呼叫new運算元實例化物件,除了最基底的類別或物件圖的葉類別,其餘有與其他類別互動的類別,應該請求物件
- 將業務類別與建構類別分開,測試會變得容易,因為可以將業務邏輯與建構邏輯分別獨立測試
- 若將業務與建構邏輯混淆,測試建構邏輯時還不得不跑業務邏輯做的事
- 問:是否建議不需要假(dummy)物件?
- 答:否,當測試的時候,無關的物件可以傳空物件進行無操作(NOP),空物件是假物件更強的表現形式
沒有留言:
張貼留言