S.O.L.I.D原則

講師: Will保哥

課程:.NET 技術講座:打造堅固耐用的 C# 程式碼

圖片來源: Will保哥 .NET 技術講座:打造堅固耐用的 C# 程式碼 課程投影片

  • 耦合度

    耦合度越高,代表程式之間的相依性越高,容易造成改A壞B的情況(==耦合是不可避免的==)

  • 內聚力

    在一個模組內只完成一件事情,意味著這個模組可以被重複利用(例如發送通知) 低內聚的表現,意味著將所有的功能都寫在同一個class,造成難以維護、理解

內聚力越高,類別越多,耦合度會增加

耦合度越低,類別越少,內聚力降低

兩者是互相衝突的,要靠當下的情境來判定使用

學習S.O.L.I.D物件導向設計原則的好處

  • 降低程式碼複雜度
  • 較佳的程式碼可讀性
  • 提升模組可重複利用姓
  • 使模組具有高內聚低耦合
  • 面臨需求變更時可減少破壞現有模組的風險

S.O.L.I.D

  • 單一責任原則SRP (Single Responsibility Principle)

    SRP主要精神就是提高內聚力。每個類別盡量只做一件事。

    • 常見問題: 1.類別複雜度過高 2.維護時找不到要改哪 3.發生邏輯問題時找不到Bug在哪 4.使用類別時不知道應該呼叫哪個方法
    • 使用時機:
      1. 在確認需求的情況下,如果只有一個類別需要用到這個方法,那就==不需要額外拉出==一個新的類別來為了做到SRP。
      2. 類別中有一段程式碼有重複利用的需求。
      3. 系統中有非必要的功能(未來的需求),老闆逼你要實作時,責任會依附在類別中,對維護造成困擾,這時候就可以透過SRP來實作。
  • 開放封閉原則OCP (Open Closed Principle)

    開放擴充但封閉修改 藉由新的程式碼來擴充系統的功能,而不是藉由修改已存在的程式碼來擴充系統

    • OCP的使用時機:

    既有的類別已經被清楚定義,處於一個強調穩定的狀態 需要擴充現有的類別,加入新的屬性或方法 擔心修改現有的程式碼會破壞現有系統的運作 系統開始設計時就決定要採用OCP模式 ==可以透過"介面"或"抽象類別"進行實作==

  • 里氏替換原則LSP (Liskov Substitution Principle)

    建議使用==介面==來實作LSP,來降低耦合度。 LSP在實作時,要注意,實作的方式是否正確 ==子類別替換基底類別的時候不會報錯==

  • 介面隔離原則ISP (Interface Segregation Principle)

    把不同的屬性和方法,放在不同的介面中 特定需求沒用到的方法,不要加入介面中 使系統可以容易的達成鬆散耦合,安全重構,功能擴充

    • ISP的使用時機:

    當介面需要被分割的時候 假設類別有20個方法,並實作一個有15個方法的介面 有某個用戶端只會使用該類別中的10個方法 你就可以為這類別的10個方法定義介面並設定實作介面 你的用戶端就可以改用介面操作 這個過程可以用來降低主程式與這個類別的耦合力

  • 不符合ISP介面隔離原則,==BeginTransaction沒有被使用到==

  • 符合ISP介面隔離原則,==沒有用到的方法應該額外獨立出來==

  • 讓使用者可以自行決定要實作哪個介面,若使用不存在的則會報錯

  • 相依反轉原則DIP (Dependency Inversion Principle)

    所有類別都要相依於抽象,而不是具體實作 可透過DI Container達到目的 為了要達到類別間鬆散耦合的目的 開發過程中,所有類別之間的耦合關係一律透過抽象介面

    • 關於DIP的實作方式
    • 型別全部都相依於抽象,而不是具體實作
    • 經過套用DIP之後,原來有相依於類別的程式碼
    • 都改成相依於抽象型別
    • 從緊密耦合的關係變成鬆散耦合關係
    • 可以依據需求,隨時抽換具體實作類別

    關於DIP的使用時機:

    • 想要降低耦合的時後
    • 希望類別都相依於抽象,讓團隊更有效率的開發系統
    • 想要可以替換具體實作,讓系統變得更有彈性
    • 符合DIPP通常也意味者符合OCP與LSP原則
    • 只要再多考量SRP與ISP就很棒了
    • 想要導入TDD或單元測試的時候