物件導向程式設計基本原則 - SOLID
其實網路上對SOLID的探討及見解文章已經多不勝數。筆者在此僅記錄自身見解與歷程。
若對該原則理解有誤,請不吝指教。
若對該原則理解有誤,請不吝指教。
SOLID?
在程式設計的領域中,SOLID指物件導向編成和物件導向設計的五個基本原則。當這些原則一起被應用時,可以使程式設計師開發一個容易擴充及維護的系統。SOLID所包含的原則是通過引發編程者進行軟體原始碼代碼重構的代碼異味清掃。從而使軟體清晰可讀及具可擴展性。SOLID被典型的應用在測試驅動開發上,且是敏捷開發及自適應軟體開發的基本原則重要組成部分。
S: Single responsibility principle(SRP) 單一職責
所謂單一職責指的是單一類別只負責一件事情。
會員類別只負責會員資料相關調整不會調整到會員訂單。訂單類別只負責訂單方面操作不會影響到商品。商品類別只負責商品欄位操作….
舉個例子:一部車子要是他同時有飛機的飛天功能、船的航海功能甚至戰車的發射大砲功能。那駕駛車的人不就除了汽車駕照之外還要去學怎麼開飛機駕船或開戰車。
車子只做好他的責任,在路上行使。路上行駛的動作可由前進、左轉、右轉、煞車等基本功能組成。
而從另一個角度看,要注意功能被切的太細碎造成過度設計(over design)的情況。車子的組成殼拆分為方向盤、燈、引擎、汽缸等…每個零件都有不同的功能(拆分為物件)。但駕駛員只要知道車子怎麼開就好。維修技師才需要去理解車子的細部功能。因此要如何規劃及定義類別的責任是很抽象且很難釐清的事情。
會員類別只負責會員資料相關調整不會調整到會員訂單。訂單類別只負責訂單方面操作不會影響到商品。商品類別只負責商品欄位操作….
舉個例子:一部車子要是他同時有飛機的飛天功能、船的航海功能甚至戰車的發射大砲功能。那駕駛車的人不就除了汽車駕照之外還要去學怎麼開飛機駕船或開戰車。
車子只做好他的責任,在路上行使。路上行駛的動作可由前進、左轉、右轉、煞車等基本功能組成。
而從另一個角度看,要注意功能被切的太細碎造成過度設計(over design)的情況。車子的組成殼拆分為方向盤、燈、引擎、汽缸等…每個零件都有不同的功能(拆分為物件)。但駕駛員只要知道車子怎麼開就好。維修技師才需要去理解車子的細部功能。因此要如何規劃及定義類別的責任是很抽象且很難釐清的事情。
Open/close principle(OCP) 開放/封閉原則
物件導向程式設計最重要的開放(擴充)封閉(修改)原則。一套系統應保有彈性,可以擴充新功能。若裡面程式碼的耦合度(Coupling)過高,新增功能時可能會影響舊功能,甚至造成BUG。所以舊程式碼應該是封閉修改的。
以車子來說,設計時就要對車上不同的功能做模組化。此時車上個功能零件車燈、輪胎、引擎等皆被抽出去做個別套件。若想將車燈改的又大又白閃瞎別人,技師緊要將燈泡換掉,不需也不必要車上其他功能(車子其他部分封閉修改);又或者因為下雪要在輪子上加上雪鍊(輪胎套件新增自己的掛上雪鍊),也不需要調整到其他舊有的汽車零件。
以車子來說,設計時就要對車上不同的功能做模組化。此時車上個功能零件車燈、輪胎、引擎等皆被抽出去做個別套件。若想將車燈改的又大又白閃瞎別人,技師緊要將燈泡換掉,不需也不必要車上其他功能(車子其他部分封閉修改);又或者因為下雪要在輪子上加上雪鍊(輪胎套件新增自己的掛上雪鍊),也不需要調整到其他舊有的汽車零件。
開放/封閉就如同字面上的,開放新增(新功能)然而封閉修改(就功能)。
L: Liskov substitution principle(LSP) Liskov替換
白話一點就是,我建立一個父類別,然後隨意new子類別並調用裡面任意方法。程式都該正常執行而不會出錯。
里氏替換至少擁有下列兩種含義:
- 若繼承是為了實現代碼重用(共享方法),那共享的父類別方法應該保持不變,不能被子被別重新定義。子類別僅能透過添加方法來擴充功能。
- 若繼承是為了多態,那父類別應該以抽象方法方式,讓子類別重新定義該方法邏輯。
依車子來說,車子定義了一個動作稱為在路上跑(Run)。而建造了三台車:跑車、房車、樂高車接繼承了車子的定義。但樂高車因為沒有引擎而不能執行路上跑(Run)的動作。故他違反了里氏替換原則。子類別應該要能執行父類別任何方法。
I: Interface Segregation Principle(ISP) 介面隔離
將不是所有人都必要的功能從介面中抽出。
若是將功能方法一股腦地寫入統一介面,可能使類別A、類別B在實作上繼承(實作)倒不必要方法。若發現有方法可能是非必要的(不是所有人都會去使用到)。可以將她拆出,形成介面隔離。
若是將功能方法一股腦地寫入統一介面,可能使類別A、類別B在實作上繼承(實作)倒不必要方法。若發現有方法可能是非必要的(不是所有人都會去使用到)。可以將她拆出,形成介面隔離。
承接上述里氏替換(LSP)原則舉例舉例來說。若只要是能在車庫內展示的皆可稱為車子。那上述樂高車就不能因為不能再路上跑(Run)而不能被稱為車子。
此時可以將路上跑的功能細分拆出新定義可以跑的車(並繼承原車子定義)。此時樂高車繼承車子定義,跑車跟房車繼承可以跑的車定義。這樣三部車皆可稱之為車子。且樂高車也不會被受限於路上跑的功能。
此時可以將路上跑的功能細分拆出新定義可以跑的車(並繼承原車子定義)。此時樂高車繼承車子定義,跑車跟房車繼承可以跑的車定義。這樣三部車皆可稱之為車子。且樂高車也不會被受限於路上跑的功能。
D: Dependency Inversion Principle(DIP) 依賴反轉
依賴反轉有以下兩項定義:
- 高層模組不應該依賴底層模組,它們都應該依賴抽象。
- 抽象不應該依賴細節。細節應該依賴抽象。
即不可再套件內寫死使用的底層模組,這樣會導致程式對該模組過度依賴(只要該模組不存在程式即不能執行)。
依上述例子延生。今日要開一場車展。那不可將程式寫死,展示車輛:跑車。
這樣要是跑車被開出去不在家。那車展不就開天窗了。
倘若展示車輛:車子,那即使跑車不在。推出樂高車與房車。皆可完成車展任務(樂高車及房車皆符合車子定義:展示)。
依上述例子延生。今日要開一場車展。那不可將程式寫死,展示車輛:跑車。
這樣要是跑車被開出去不在家。那車展不就開天窗了。
倘若展示車輛:車子,那即使跑車不在。推出樂高車與房車。皆可完成車展任務(樂高車及房車皆符合車子定義:展示)。
—————————-
工程師最怕聽到的就是程式又要改。
而SOLID原則是前人經過無數經驗統整出使程式具備容易維護且拒可擴充性質。讓之後在更動程式或擴充需求時能降低修改既有程式難易度。
雖說SOLID原則能使程式品質有實質的耀生,但還是得注意別陷入過度設計。
而SOLID原則是前人經過無數經驗統整出使程式具備容易維護且拒可擴充性質。讓之後在更動程式或擴充需求時能降低修改既有程式難易度。
雖說SOLID原則能使程式品質有實質的耀生,但還是得注意別陷入過度設計。
留言
張貼留言