1. 程式人生 > >《轉》面向對象類設計原則

《轉》面向對象類設計原則

href 編程 相等 tro 設計時 對象 函數參數 種子 代碼

面向對象類的設計原則

1 SRP(單一職責原則)

這個原則看起來很簡單,就是說一個類只能承擔一個職責

但這裏有一個關鍵:“職責”是如何理解的?

按照漢語的理解,職責其實分為兩部分:“職”和“責”。“職”就是這個類是什麽,而“責”就是這個類要幹什麽

舉個例子來說:Door是一個對象,那麽它的“職”就是門,“責”就是“開門、關門”等;而Lock“職”就是鎖,“責”就是“上鎖、開鎖”。如果設計的時候Door同時具有鎖的職責,那麽Door就違反了SRP原則。

2 OCP(開閉原則)

相信這是大家見得最多的原則,而且很多人都是這麽解釋的

對擴展開放、對修改封閉”,更加有人總結為“不修改代碼增加新的功能”!

太神奇了,不修改代碼增加新的功能!但我不免疑惑:不修改代碼怎麽增加新的功能呢?難道代碼會像生物一樣,基因變異?

仔細研究過後才發現,原來是這些總結的人誤導了我,根本不是什麽“不修改代碼增加新的功能”,也不是那個省略了主語的“對擴展開放,對修改封閉”,而是“被調用者開放擴展,調用者封閉修改

還是舉門的例子:Door對象是被其它對象例如人People調用,那麽Door就是被調用者,People就是調用者。Door對象可以擴展為“防盜門”、“防火門”、“逃生門”等,但People在調用的時候不需要關註具體是什麽門,只需要調用這些門公共的

“開門、關門”等操作即可。

3 LSP Liskov替換原則)

這個看起來是比較難理解的原則,但我可以給一個很容易理解的總結:子類的輸入不能比父類多,子類的輸出不能比父類少!”。

“輸入”就是指調用類的時候要給出的條件,最常見的就是函數參數,而一般的語言都可以從語法上保證這種子類和父類相同函數的參數必須相同;還有另外一種隱性的條件即“假設”或者“要求”也必須相同。

舉個簡單的例子:長方形和正方形。按照數學的定義,正方形是特殊的長方形。依照此定義看起來好像可以將正方形定義為長方形的子類,但實際上在面向對象設計中則是不行的,因為按照設定長方形長寬的方法不能來設定正方形的邊長,正方形要求長寬必須相等,而長方形沒有此

“要求”。這就是子類的“假設”或者“假設”多於父類,違反了LSP原則。

“輸出”就是指調用類後返回的結果。即:子類的返回結果要包含父類的返回結果,可以多但絕對不能少。

為什麽設計時要滿足LSP原則呢?其實很簡單,因為調用者看到的只有父類,它根本不知道到底是哪個子類,調用者所有的處理都是基於父類提供給調用者的信息(包括輸入信息和輸出信息)。

4 DIP(依賴反轉原則)

這個原則看起來有點嚇人,換個簡單的說法你就明白了,其實它就對應於《設計模式》開頭提到的兩個原則中的一個:基於接口編程,而不是基於實現編程”。(另外一個是什麽呢?)

這裏的“編程”包括“調用者”和“被調用者”的編程。“調用者”基於接口進行調用,“被調用者”基於接口進行具體實現。

註意:和“依賴反轉”類似的兩個比較容易混淆的概念是“依賴註入”和“控制反轉”,詳細可以參考如下博文:http://blog.csdn.net/taijianyu/archive/2008/04/28/2338311.aspx

5 ISP(接口隔離原則)

這個原則也很簡單,就是說一個對象不要提供多個接口,不同的接口應該分離到不同的對象上去。

雖然大師的水平不容懷疑,但這裏我還是要懷疑一下:SRPISP本質上應該是一個原則,只是說法不一樣而已

為什麽這麽說呢?大家可以看看SRP原則,它說的是“單一職責”。那麽職責最終體現在對象上是什麽呢?對,不就是接口麽!也就是說,如果遵循了SRP原則,接口自然就隔離了。

《轉》面向對象類設計原則