Single-responsibility principle (SRP) 單一職責原則

一個模組應該只對唯一的一個角色負責

Huashen
Mar 22, 2021

什麼是SRP

單一職責原則,簡稱SRP(Single-Responsibility Principle),核心概念是一個模組應該只對唯一的一個角色負責。SRP旨在分離所有責任不同的程式碼為不同的模組,以求更好的可讀性穩定性擴展性

為什麼要有SRP

沒有做好SRP的程式碼,常常會發生一件事,就是建構出基本的原型之後,便不斷的在上面加入新的功能,完全忘記要區分責任,也沒有切分功能,導致一個數百到上千行程式碼的誕生,先別管可讀性了,光一個打錯字或是引用錯誤都很有可能造成極大的問題,這就是BUG與他們的產地

如何做到SRP

我們先來看看如果沒有SRP的狀況:

在這裡我們定義了一個撲克牌遊戲的原型,我相信通常第一眼看下來一定會覺得霧煞煞,搞不清楚我們在做什麼,不過沒關係,我們先讓他跑起來。

為了方便我們分類,我們在src資料夾中創建一個叫做SRP的資料夾,把這個檔案命名為Bad.ts,放在SRP裡面,同時修改src裡的index.ts:

import { BadGame } from './SRP/Bad';new BadGame();

與之前同樣,開啟兩個Terminal,分別輸入:

yarn watchyarn start

應該就可以看到Game Start!訊息,並且把我們的手牌列印出來。

它做了什麼?

這段程式碼既沒有註解,也沒有良好的命名,更不要說邏輯混亂,全部混在一起,這樣的程式碼是非常糟糕的,先不說將程式交接給他人,就算是自己要維護也是非常困難。打個比方,這份程式碼為了偷懶省字數,選用了一個很差的洗牌方法,現在我們必須將它替換掉,有辦法找到它在哪裡嗎?

this.deck.sort(() => 0.5 - Math.random());

就是這一行,先撇開背後的原理,光要找到它就十分困難了,我們還要去判斷這段程式碼是否真的是所謂的洗牌方法,而且會不會我一改動,反而影響到其他功能。要知道在程式設計師在解決問題時,大部分的時間都是花在尋找問題,剩下來的時間才是寫Code,因此這種寫法只會徒增未來的維護成本而已。

話又說回來,我們剛剛說要改掉這個洗牌方法,稍加修改後變成這樣:

好吧,這下當我們下次有需要新增或更改邏輯時又更加混亂了,可以預見在未來,這段程式碼將會越來越龐大,也沒有人想動它,最後只能乾脆整份重寫的結局。

重構

我們先將程式碼複製到Good.ts裡面,接著進行基本的重構,將Card類別抽出來,並將所有功能用函數封裝起來,明確的命名各個功能,把原先的類別改叫GoodGame,完成後大致上會長這樣:

這是分離出來的Card.ts,這部分我們就不太需要進行重構了。

別忘了修改我們的index.ts,我們把原先的程式碼註解掉,並加上新的:

// import { BadGame } from './SRP/Bad';// new BadGame();import { GoodGame } from './SRP/Good';new GoodGame();

接著一樣重新執行我們的指令,watch會一直監看,因此我們只需要:

yarn start

應該可以看到我們的程式仍然運行良好,但程式碼已經乾淨整潔了許多。

所以那個SRP?

並不是重構完就一定符合SRP的要求,所以讓我們再次回顧一下SRP原則:

一個模組應該只對唯一的一個角色負責

在TypeScript中,模組是以不同的.ts檔案區隔開的,以目前的架構來說,我們的Card只負責跟卡片有關的事(目前只有toString),但是我們的GoodGame裡面又有許多私有方法是在操作Deck,那不如分離出Deck這個模組。

可以看到,我們把Deck分離出來並稍微改寫之後,這個類別裡所有的方法都是跟牌堆有關的,我們也新增了一些功能,讓外界更好使用這個模組,只要所有方法都是跟牌堆操作有關,就仍然是符合SRP原則的。

我們的GoodGame經過修改變成了這樣。因為我們把Deck封裝起來,所以就算修改Deck也不會影響到GoodGame,反之若需要在GoodGame裡面新增功能,也不容易干擾到Deck本身的狀態,如此一來能夠讓後續的擴充變得更容易。這裡順便把牌堆印出來證明我們真的有洗牌。

這樣就算是完成了單一職責原則要我們做的事了。

總結一下

在程式設計之初,我們就應該時常審視自己的程式碼,每當我們修改了一段程式,都必須再重新思考是否有符合SRP原則。若是沒有,就是需要進行重構的時間了,及早進行重構才不會留下技術債,否則最後苦惱的可能就會是你的主管、同事、甚至是你自己了。

下一篇文章 <Open–closed principle 開放封閉原則>

如果對於我的文章或程式碼有任何問題,歡迎在下方留言指教。

若有幫助到你,也歡迎給文章拍手一下,讓我在寫文章的路上更加進步!

--

--

Huashen

嗨,我是Huashen,一位軟體工程師,這裡會記錄我的程式設計心得與筆記。