.NET Core TDD 前傳: 編寫易於測試的代碼 -- 單一職責 ...
第1篇: 講述了如何創造"縫". "縫"(seam)是需要知道的概念.
第2篇, 避免在構建對象時寫出不易測試的代碼.
第3篇, 依賴項和迪米特法則.
第4篇, 全局狀態引起的問題.
本文是第5篇, 也是最後一篇, 介紹的是單一職責
類做了太多的工作
例子, 某軟體公司, 原有項目開發, 測試, 售前, 售後, 財務等員工. 後來由於公司沒錢, 裁掉了測試, 讓開發兼職; 過了段時間, 又裁掉了需求和售後, 還是由你這個開發來兼職; 再過了段時間, 又裁掉了財務和售前, 還是由你來兼職.
某天上班之後, 你剛想寫代碼, 就接到了客戶來電, 說鍵盤不好用, 讓你去給調試一下. 花了1個小時從客戶那裡調試回來又剛想寫點代碼, 某客戶說發票沒給, 你又去快遞發票. 回來之後又想寫代碼, 又有客戶來電話咨詢你公司的XXX管理系統, 經過半個小時的講解, 客戶沒興趣. 這時已經到了中午, 你卻發現你的本職工作一點都做.
在現實世界中, 給某個員工賦與很多衝突的角色或職責是很不明智的.
在軟體開發里也是這樣的, 在為一個類賦予太多的職責會引出很多維護和測試的問題.
單一職責
單一職責是面向對象軟體設計的準則之一, 它說的是: "一個類只能因為一個原因去改變".
這就是說我們應該增加 因為相同原因而做出改變的東西 的內聚性, 而降低 由於不同原因而做出改變的東西 的耦合性.
這句話通常被描述為: "一個類或一個方法只應該做一件事情, 並且要把它做好".
如果一個類有了太多的職責, 那麼職責間的交互就會埋藏於類里, 這樣做就很難一次修改一個職責. 對於測試來說, 這些交互之間也沒有明顯的"縫隙".
依賴項的構建工作並不是目標類本身的職責, 這項工作應該和類本身的職責分開. 所以我們會使用依賴註入配置好的對象. 我們應該對類進行抽取, 讓其成為單一職責的類.
引起的問題
如果一個類有多個職責, 那麼在測試上它會有以下問題:
- 如果一個類/方法有太多的功能, 那麼針對它的測試就會特別多, 很容易讓人難於理解也很難維護.
- 測試的設置也會更加的麻煩.
- 由於有多個原因去修改該類, 那麼它的測試類/方法就會修改的更加頻繁.
危險信號
什麼樣的類/方法會違反單一職責呢?
- 如果你在描述該類功能的時候用到了"和", "或", "還", "並且"等詞.
- 類或者方法的代碼很多.
- 註入了太多的依賴項.
- 一個類改變的太頻繁了也可能意味著這個類的職責可能不止一個.
解決方案
如果一個類有很多職責, 那麼可以這樣做:
- 識別出類裡面各個獨立的職責.
- 給每個職責貼上標簽.
- 解耦, 把其它功能抽取到單獨的類, 最後保證每個類都是單一職責.
例子
舉一個很簡單的典型例子:
這個類, 有4個依賴項, 不算特別多, 但是也不少. 它的名字在這裡就是它的描述, 裡面包含了"或"的意思. 在它的方法參數里, 有一個標識, 像這樣會改變方法的高級行為的標識, 通常就意味著該方法會有不止一個職責. 而方法體裡面, 我們可以看到它確實有兩個職責, 分別是發送郵件和打電話給客戶.
優化後
經過識別, 抽取後, 該類應該分成下麵兩個類:
EmailCommand:
CallCommand:
這個系列的帖子就到這了.
下麵開始介紹TDD.