➣ Reading Time: 7 minutes

前言

在程式碼優化中,我們可以想像如果我們能將每一個功能拆的非常的精細
(例如一個函數 (function) 只會有屬於他的單一功能)

這部份也是 OOP (物件導向程式設計、Object Oriented Programming) 所強調的精神之一
“S”OLID 物件導向設計原則中的 “S” 指的就是 Single Responsibility。

以個人經驗來說,可以得到以下的好處:

  1. 除錯(debug) 單一功能的問題:只需針對單一函數 (function) 去做 debug
  2. 維護(maintain) 程式碼的單一功能:只需維護單一函數 (function)
  3. 修改(modify) 程式碼的單一功能:只需修改單一函數 (function)
  4. 程式碼可讀性 (readability) :可以明確知道此函數就是針對單一功能去做撰寫,在大型系統系統中如果一個函數做太多功能,「別的工程師」在閱讀時也必須去了解此函數中更多程式碼的細節。
  5. 程式碼可重用性 (reusability):如果每一個功能都拆的很乾淨,有時類似功能的單一函數相對容易做重複使用。

還有很多的好處,雖然以上看起來像在講廢話(欸),
實際上要去「實踐」這件事與「了解」這件事情完全是兩回事XD,
我自己也正努力在「優化程式碼」的學習路上。

SRP (單一職責原則、Single Responsibility Principle)

原文 (Robert C. Martin)

A class should have only one reason to change

自己的解釋

降低單一功能當需要「改變」時,影響整體系統的機會。

講完了。你說「蛤?」
沒辦法這概念就這麼抽象XDDD,試著舉一個例子也許比較好懂。

我想要定義一支狗的類別:

class Dogs:
    # 建構式
    def __init__(self, name, sex):
        self.name = name  # 姓名屬性
        self.sex = sex  # 性別屬性

假設我們知道了,「肚子餓」或「受傷」都會讓狗生氣。
我們可以這樣增加功能:

class Dogs:
    # 建構式
    def __init__(self, name, sex):
        self.name = name  # 姓名屬性
        self.sex = sex  # 性別屬性

    # 方法(Method)        
    def hungry(self):
        print("The dog is angry.")

    def hurt(self):
        print("The dog is angry.")  

我們可以看到不論是 hungry(self), hurt(self)
都會觸發狗生氣的反應。

但是上面的寫法並沒有運用到 SRP 的觀念
我們假設我們想要增加狗「生氣」時會有的其他反應,
有沒有發現同樣的功能我們可能需要改兩次一樣的東西?

那我們在仔細想一下,現實中會有更多種可能會觸發狗「生氣」的方法,
上面的方法雖然寫的快速又直接明瞭,但相對來說碰到修改「生氣」的功能時,
變成「全部」都要慢慢一個個改。

於是參照SRP 的觀念
我們定義了一個「生氣」的方法,象徵了當狗生氣時可能會有的反應。

class Dogs:
    # 建構式
    def __init__(self, name, sex):
        self.name = name  # 姓名屬性
        self.sex = sex  # 性別屬性

    # 方法(Method)
    def angry(self):
        print("The dog is angry.")

    def hungry(self):
        self.angry()

    def hurt(self):
        self.angry()    

這樣就能夠解決我們上述所說的,當我們想增加「生氣」會有的反應時,
我們不需要全部一個個慢慢改動功能。

也就是 SRP (Single Responsibility Principle) 所提倡的單一職責原則。

使用情境、優缺點

上面的例子中,我們也看到大型程式中,SRP 的效果才會明顯的被展現,
如果只是小程式講究快速開發,也許 SRP 有時候開發效率不見得會高,
但維護功能上,我們也能看出 SRP 在大型系統的重要之處。
我們只需要針對單一函數 angry(self) 去進行維護即可。

若沒有使用 SRP ,維護上我們必須一個個函數去查看。
就如同上述例子,我們必須同時修改hungry(self), hurt(self)的功能。
更何況是更大型的系統,未使用 SRP 維護會更缺乏效率的。

Reference

https://wadehuanglearning.blogspot.com/2019/12/blog-post.html
http://teddy-chen-tw.blogspot.com/2014/04/solid.html
https://ithelp.ithome.com.tw/articles/10191955
https://www.learncodewithmike.com/2020/01/python-class.html
https://www.learncodewithmike.com/2020/01/python-method.html
https://weilihmen.medium.com/%E9%97%9C%E6%96%BCpython%E7%9A%84%E9%A1%9E%E5%88%A5-class-%E5%9F%BA%E6%9C%AC%E7%AF%87-5468812c58f2