物件導向設計(OOP,Object-Oriented Programming)本身具有封裝、繼承、多型、抽象的特性,而在物件導向程式中,遵循SOLID這五項基本原則:單一職責、開放封閉、里氏替換、介面隔離、依賴反轉,幫助程式設計師寫出更容易開發、維護、容擴充的程式系統架構。
所謂單一職責就是指一個類別只負責一件事情,換句話說就是不要讓一個類別負責太多不相關、或發散的功能,一個類別承擔,被切成太多、太碎的設計(Over Design)會讓之後的使用、維護、變更、擴充上都會造成困擾,注意這不是指一個類別裡面只放一個方法。
要怎麼規劃一個類別的職責,需要視實際的需求而定,如何定義一個類別(物件)的職責是一個很抽象也很難釐清的事情,我們在這邊只能大概的簡介一下,最重要還要您實際下場開發取得經驗後,就會在日後規畫時,更能更精準地掌握一個類別要負責的職責範圍了。
在一個系統中,子類別應該可以替換掉父類別而不會影響程式架構。
阿文要開車去外婆家,阿文家車庫裡面有很多台車,我們先看其中三台車,如下圖:
阿文坐上的樂高車後,發現這是樂高積木組成的模型車,沒有引擎,根本不能上路!!!
這時候子類別樂高車並沒有辦法執行父類別car的路上跑功能,這種情況就不符合Liskov替換原則,子類別應該可以執行父類別想做的事情。
把不同功能的功能從介面中分離出來。
阿文表示,上次要去阿嬤家算是特殊的需求,我家的車最主要就是拿來佔車庫避免空間浪費, 然後輪流擺在庭院炫富用,樂高車也可以算是一台車,我們來看看阿文家的車庫:
這邊有一個小問題,發現了嗎?對阿文來說,車子不一定要有「路上跑」這個功能,阿文的樂高車是沒辦法在路上的跑的,這明顯違反了上一條LSP,因此我們必須修改車子的定義 ,大部分的車有「路上跑」功能,因此我們可以將這個功能分割到其他介面,分割後如下圖,如此一來我們就用介面隔離「路上跑」這個功能:
定義:高階模組不應依賴低階模組,兩個都應該依賴在抽象概念上;抽象概念不依賴細節,而是細節依賴在抽象概念。
上面這段文字看起來很抽象,讓我來翻譯翻譯,意思就是「話不能說的太死,盡量講一些概念性的東西」。
阿文要在庭院要弄一個賞車派對,邀請函上面寫著「阿文誠摯邀請您來欣賞Ferrari Fx2020超級跑車」,因此這個派對就會被綁死在Fx2020超級跑車上面。如果當天阿文的爸爸開著這輛車去打網球,阿文在開趴那天就很糗很糗了。
為了避免這種事情發生,邀請函上面最好是寫著「阿文誠摯邀請您來參加派對並且欣賞超級跑車」,這樣一來就算當天阿文爸把Ferrari Fx2020開走了, 他只要另外拿出一台超級跑車就可以,雖然朋友們會有受騙的感覺,不過至少不會讓阿文當場丟盡面子。
在軟體開發過程中,程式設計師最常抱怨的一句話:
什麼,又要改,是要改幾次阿!!!?
在實務上,不論事前如何小心規劃設計系統架構,我們還是會常常遇到需求變更、需求理解錯誤或是bug修改等會讓程式設計師需要不斷調整修改程式碼的情況。不論是上面那些出自於「Agile Software Development」這本書的五項原則或是本書的主題「設計模式」,都是前人在軟體開發過程中所累積的經驗心得,可以說是學習寫程式的內功心法,而這些心法有一個共同的目標,為了讓程式碼更容易維護並且維持軟體的可擴充性,讓我們在改動程式碼的時候,工作可以順利一點,痛苦指數也可以下降一點。