物件導向程式設計基本原則 - SOLID

物件導向設計(OOP,Object-Oriented Programming)本身具有封裝、繼承、多型、抽象的特性,而在物件導向程式中,遵循SOLID這五項基本原則:單一職責、開放封閉、里氏替換、介面隔離、依賴反轉,幫助程式設計師寫出更容易開發、維護、容擴充的程式系統架構。

 

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

所謂單一職責就是指一個類別只負責一件事情,換句話說就是不要讓一個類別負責太多不相關、或發散的功能,一個類別承擔,被切成太多、太碎的設計(Over Design)會讓之後的使用、維護、變更、擴充上都會造成困擾,注意這不是指一個類別裡面只放一個方法。

要怎麼規劃一個類別的職責,需要視實際的需求而定,如何定義一個類別(物件)的職責是一個很抽象也很難釐清的事情,我們在這邊只能大概的簡介一下,最重要還要您實際下場開發取得經驗後,就會在日後規畫時,更能更精準地掌握一個類別要負責的職責範圍了。

 

O: Open/Close Principle(OCP) 開放/封閉原則

開放/封閉原則就如同字面上的意思,開放新增功能,封閉修改其他不相關的功能。

物件導向程式設計最重要的開放(擴充)封閉(修改)原則,簡單的說就是,當新增需求的時候(功能變化),在不改變現有程式碼的前提之下,藉由增加新的程式碼來實作新的功能。

如果程式裡面的程式碼的耦合度(Coupling)太高,在新增功能擴充時,就可能會影響舊功能,甚至造成程式的錯誤,因此在新增功能時,就必須要非常非常的小心謹慎,以避免將原本正常程式碼給改壞了,這樣就違反了一套程式應該要保留彈性,還要可以擴充新功能的原則。

另外高耦合的程式碼,在出現程式錯誤需要維護修改時也會發現同樣的麻煩,有鑑於此,舊程式碼應該是封閉修改的,或是某個舊功能需要調整,也不應該取影響到其他功能。

 

L: Liskov Substitution Principle(LSP) 里氏替代原則

在一個系統中,子類別應該可以替換掉父類別而不會影響程式架構。
阿文要開車去外婆家,阿文家車庫裡面有很多台車,我們先看其中三台車,如下圖:


阿文坐上的樂高車後,發現這是樂高積木組成的模型車,沒有引擎,根本不能上路!!!
這時候子類別樂高車並沒有辦法執行父類別car的路上跑功能,這種情況就不符合Liskov替換原則,子類別應該可以執行父類別想做的事情。

 

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

把不同功能的功能從介面中分離出來。

阿文表示,上次要去阿嬤家算是特殊的需求,我家的車最主要就是拿來佔車庫避免空間浪費, 然後輪流擺在庭院炫富用,樂高車也可以算是一台車,我們來看看阿文家的車庫:


這邊有一個小問題,發現了嗎?對阿文來說,車子不一定要有「路上跑」這個功能,阿文的樂高車是沒辦法在路上的跑的,這明顯違反了上一條LSP,因此我們必須修改車子的定義 ,大部分的車有「路上跑」功能,因此我們可以將這個功能分割到其他介面,分割後如下圖,如此一來我們就用介面隔離「路上跑」這個功能:


D: Dependency Inversion Principle(DIP) 依賴反轉原則

定義:高階模組不應依賴低階模組,兩個都應該依賴在抽象概念上;抽象概念不依賴細節,而是細節依賴在抽象概念。
上面這段文字看起來很抽象,讓我來翻譯翻譯,意思就是「話不能說的太死,盡量講一些概念性的東西」。

阿文要在庭院要弄一個賞車派對,邀請函上面寫著「阿文誠摯邀請您來欣賞Ferrari Fx2020超級跑車」,因此這個派對就會被綁死在Fx2020超級跑車上面。如果當天阿文的爸爸開著這輛車去打網球,阿文在開趴那天就很糗很糗了。

為了避免這種事情發生,邀請函上面最好是寫著「阿文誠摯邀請您來參加派對並且欣賞超級跑車」,這樣一來就算當天阿文爸把Ferrari Fx2020開走了, 他只要另外拿出一台超級跑車就可以,雖然朋友們會有受騙的感覺,不過至少不會讓阿文當場丟盡面子。

 

在軟體開發過程中,程式設計師最常抱怨的一句話:
什麼,又要改,是要改幾次阿!!!?
在實務上,不論事前如何小心規劃設計系統架構,我們還是會常常遇到需求變更、需求理解錯誤或是bug修改等會讓程式設計師需要不斷調整修改程式碼的情況。不論是上面那些出自於「Agile Software Development」這本書的五項原則或是本書的主題「設計模式」,都是前人在軟體開發過程中所累積的經驗心得,可以說是學習寫程式的內功心法,而這些心法有一個共同的目標,為了讓程式碼更容易維護並且維持軟體的可擴充性,讓我們在改動程式碼的時候,工作可以順利一點,痛苦指數也可以下降一點。

 

  • Top