iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 9
4
Software Development

保持前進、持續優化程式碼內涵系列 第 9

09. 物件導向設計原則—SOLID

在前文物件導向的特性中,提到物件導向設計本身具有封裝繼承多型抽象這些特性。

知道物件導向的特性,就可以寫出具備閱讀性維謢性擴充性的程式碼?答案是肯定的,但卻非常的困難。之所以困難,常見的因素列表如下。

  • 為了方便,類別函數全部設為 Public。(未有效使用封裝的特性。)
  • 單一類別中,混雜了許多功能,導至要修改特定功能時,相關程式碼的變動量過大。(高耦合、不符合單一職責)
  • 資料與商業邏輯混雜在一起。(高耦合)
  • 當出現特定需求變更時,直接變更原本程式碼。除了可能改壞原本程式功能外,也會增加維護上的麻煩。

當然還有許多因素,是筆者沒有想到或是沒有列出來的。

使用物件導向開發軟體的過程中,如果能配上Robert C. Martin提出的物件導向設計的五個原則(SOLID):單一職責開放封閉里氏替換接口隔離以及依賴反轉。這樣會更容易開發出易維護與擴展的系統。

1. 物件導向設計的五原則 SOLID

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

每個物件,不管是類別、函數,負責的功能,都應該只做一件事。

對函數而言,一個函數內,同時做了兩件以上的事情。當發生錯誤時,很難快速定位錯誤的原因。另外,也容易間接導至程式碼的可閱讀性降低。

1.2 開放封閉原則(Open-Close principle, OCP)

藉由增加新的程式碼來擴充系統的功能,而不是藉由修改原本已經存在的程式碼來擴充系統的功能。

當需求有異動時,要如何在不變動現在正常運行的程式碼,藉由繼承相依性注入等方式,增加新的程式碼,以實作新的需求。

假若為了新需求,去修改了原本的程式中的某一個函數,可能會造成其他呼叫使用該函數的的功能,出現非預期的錯誤。

1.3 里氏替換原則(Liskov substitution principle, LSP)

Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.

簡單來說,當實作繼承了 interface 或 base-class的 sub-class,那麼在程式中,只要出現該 interface 或 base-class 的部份,都可以用 sub-class 替換。

1.4 接口隔離原則(Interface segregation principle, ISP)

針對不同需求的用戶,開放其對應需求的介面,提拱使用。可避免不相關的需求介面異動,造成被強迫一同面對異動的情況。

1.5 依賴反轉原則(Dependency inversion principle, DIP)

A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
B. Abstractions should not depend on details. Details should depend on abstractions.

當 A 模組在內部使用 B 模組的情況下,我們稱 A 為高階模組,B 為低階模組。高階模組不應該依賴於低階模組,兩者都該依賴抽象介面。

在後文從被動變主動—依賴反轉,針對這個主題,特別的提出來討論。

2. 後言

不知道各位看倌有沒有發現,SOLID 的設計原則,都是提供軟體更大的需求修改的空間。

要特別提醒的是,符合 SOLID 的開發方式,雖然較易維護與擴展。但就實務面而言,有時,必需考量使用 SOLID 額外帶來的開發時間,是否是開發期程所能承受的。

3. 推薦

3.1 文章

3.2 本屆鐵人賽的文章


上一篇
08. 物件導向的特性—封裝、繼承、多型、抽象(撰寫中)
下一篇
10. 從被動變主動—依賴反轉
系列文
保持前進、持續優化程式碼內涵24

尚未有邦友留言

立即登入留言