Try   HackMD

SOLID 之 S - 單一職責原則

一個類只有一個改變的原因

上兩篇講到 design pattern 要解決的是程式碼變動所引起的問題,但學 design pattern 要先會 SOLID 原則,SOLID 和 design pattern 是一脈相承的,所以在進入 design pattern 前先來看一下 SOLID。

關於 SOLID, iOS @ Taipei 的 William 也講過:

『SOLID 是五個關於面對變化的軟體設計原則,讓我們在改變原有程式碼或邏輯時,不會影響到其他部分和原有功能的實現,讓處理變化這件事變得容易。』

現在就來看看 SOLID 的內容吧~


Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

(By 王巍大大 @ 2019 iPlayground)

SOLID 中的 S 是指 Single Responsibility Principle,單一職責原則。

單一職責原則的概念很簡單,就是一個類或者模組只負責一項職責(功能),把不同的功能劃分開來。

正所謂:「有人的地方就有江湖,有變更的地方就有 bug」。

當一個類只有一個功能,功能要更動時只會動到相關的類或模組,這樣可以減少動到的部分,降低不確定因素和 bug 出現的可能性。

Robert Cecil Martin 定義單一職責原則為 『一個類應該只有一個改變的原因』( Class should have only one reason to change.)。

但我自己一開始看其實有點摸不著頭腦。什麼叫一個改變的原因?和單一職責有什麼關係?

這邊 Martin 其實是把責任定義為變化的原因,以一個登入頁面來舉例,我們要做出簡單登入功能讓使用者登入成功後跳轉新頁面和若登入失敗跳出登入失敗提示,當中我們需要實現的功能包括 call API 功能、頁面跳轉功能和提示視窗功能。

我們可能會寫成這樣:

https://gist.github.com/lumanmann/52958b38fc2d0bdceec48f967895275f

這樣 APP 可以跑沒錯,但不論是畫面的交互、 call API 功能、頁面跳轉功能和提示視窗功能都是寫在 LoginViewController 這個類裡面。

你會發現:

改畫面的交互,改 LoginViewController
改call API 的邏輯,改 LoginViewController
改跳轉的頁面,改 LoginViewController
改提示視窗的內容,改 LoginViewController

我們會有很多原因去動到 LoginViewController。

不同的功能像義大利麵纏繞在一起,這樣很容易改A壞B,而且可讀性低,不容易 debug,因為程式碼比李後主的心情更亂,更加剪不斷理還亂。

如果有遵從單一職責原則,類別的複雜性會降低,而且我們只有一個改變的原因去改變那個類:就是要改那個類的功能才會動它

改進的第一步

如果平常是像上面那樣寫,要突然把功能寫成不同的類應該會有難度,
我們可以先按程式碼的實際功能拆分成數個小一點的 function ,像這樣:

https://gist.github.com/lumanmann/35672ceda8152e52cdb53fa55e637f28

這樣寫每一個 function 的功能比較明確,而且行數不會過多,易於閱讀。
但現在 LoginViewController 這個類仍是負責多個職責。

更進一步

我們可以把不同 function 的功能拉出來獨立成不同的 class ,像這個專案:

https://github.com/lumanmann/single-responsibility-principle

這樣 LoginViewController 只負責 View 的交互和呈現,要改 call API 功能、頁面跳轉功能和提示視窗功能都回到它們所屬的類。

怎樣檢驗自己有沒有遵從單一職責原則?

通常,如果一個類的行數過多或是牽涉的變數和參數太多,代表它負責的事也愈多,有些功能可能可以分離開來寫。

如果你找一個功能的程式碼要花 20 秒以上,代表你的類可能太複雜了,所以不好閱讀才會找這樣久。

如果 function 有使用到 and 或 or 的字,也代表這個 function 做多於一件事。

最明顯的是當你改A壞B時,證明你的功能們有所連動。

如果你沒有以上問題,那就應該有遵從到單一職責原則。(耶~)

單一職責原則實行的難點

經驗和本職學能不足限制了我們的想像

有時候在寫專案的時候,我們可能會意識到自己的程式碼不好維護,但礙於經驗不足,我們即便想要改也無從下手。這一點沒有捷徑可走,只能透過不斷學習去解決。

其中一個很好的學習途徑是去看看大神們寫的開源碼,你會發現很多新世界。

我覺得學完 design pattern 再去看會比較適合,因為他們有用到不少 pattern ,當中的運行邏輯很不好理解,如果不懂的話去看會很吃力。但也不是不能看啦,只是個人認為一個一個 pattern 去理解後再去看複合的會比較容易懂。

總結

偷懶借 William 的 PPT 來總結一下:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

單一職責原則提倡把程式碼進行分類,但要使用得好,還是需要看需求和吃經驗。