.NET Core TDD 前傳: 編寫易於測試的程式碼 -- 單一職責

solenovex發表於2018-08-06

第1篇: 講述了如何創造"縫".  "縫"(seam)是需要知道的概念.

第2篇, 避免在構建物件時寫出不易測試的程式碼.

第3篇, 依賴項和迪米特法則.

第4篇, 全域性狀態引起的問題.

本文是第5篇, 也是最後一篇, 介紹的是單一職責

 

類做了太多的工作

例子, 某軟體公司, 原有專案開發, 測試, 售前, 售後, 財務等員工. 後來由於公司沒錢, 裁掉了測試, 讓開發兼職; 過了段時間, 又裁掉了需求和售後, 還是由你這個開發來兼職; 再過了段時間, 又裁掉了財務和售前, 還是由你來兼職.

某天上班之後, 你剛想寫程式碼, 就接到了客戶來電, 說鍵盤不好用, 讓你去給除錯一下. 花了1個小時從客戶那裡除錯回來又剛想寫點程式碼, 某客戶說發票沒給, 你又去快遞發票. 回來之後又想寫程式碼, 又有客戶來電話諮詢你公司的XXX管理系統, 經過半個小時的講解, 客戶沒興趣. 這時已經到了中午, 你卻發現你的本職工作一點都做.

在現實世界中, 給某個員工賦與很多衝突的角色或職責是很不明智的.

在軟體開發裡也是這樣的, 在為一個類賦予太多的職責會引出很多維護和測試的問題.

單一職責

單一職責是物件導向軟體設計的準則之一, 它說的是: "一個類只能因為一個原因去改變".

這就是說我們應該增加 因為相同原因而做出改變的東西 的內聚性, 而降低 由於不同原因而做出改變的東西 的耦合性.

這句話通常被描述為: "一個類或一個方法只應該做一件事情, 並且要把它做好".

 

如果一個類有了太多的職責, 那麼職責間的互動就會埋藏於類裡, 這樣做就很難一次修改一個職責. 對於測試來說, 這些互動之間也沒有明顯的"縫隙".

依賴項的構建工作並不是目標類本身的職責, 這項工作應該和類本身的職責分開. 所以我們會使用依賴注入配置好的物件. 我們應該對類進行抽取, 讓其成為單一職責的類.

 

引起的問題

如果一個類有多個職責, 那麼在測試上它會有以下問題:

  • 如果一個類/方法有太多的功能, 那麼針對它的測試就會特別多, 很容易讓人難於理解也很難維護.
  • 測試的設定也會更加的麻煩. 
  • 由於有多個原因去修改該類, 那麼它的測試類/方法就會修改的更加頻繁.

 

危險訊號

什麼樣的類/方法會違反單一職責呢?

  • 如果你在描述該類功能的時候用到了"和", "或", "還", "並且"等詞.
  • 類或者方法的程式碼很多.
  • 注入了太多的依賴項.
  • 一個類改變的太頻繁了也可能意味著這個類的職責可能不止一個.

 

解決方案

如果一個類有很多職責, 那麼可以這樣做:

  • 識別出類裡面各個獨立的職責.
  • 給每個職責貼上標籤.
  • 解耦, 把其它功能抽取到單獨的類, 最後保證每個類都是單一職責.

 

例子

舉一個很簡單的典型例子:

 

這個類, 有4個依賴項, 不算特別多, 但是也不少. 它的名字在這裡就是它的描述, 裡面包含了"或"的意思. 在它的方法引數裡, 有一個標識, 像這樣會改變方法的高階行為的標識, 通常就意味著該方法會有不止一個職責. 而方法體裡面, 我們可以看到它確實有兩個職責, 分別是傳送郵件和打電話給客戶.

 

優化後

經過識別, 抽取後, 該類應該分成下面兩個類:

EmailCommand:

 

 

CallCommand:

 

這個系列的帖子就到這了.

下面開始介紹TDD.

 

相關文章