1. 程式人生 > >設計模式之面向物件七大基本原則

設計模式之面向物件七大基本原則

PS一句:最終還是選擇CSDN來整理髮表這幾年的知識點,該文章平行遷移到CSDN。因為CSDN也支援MarkDown語法了,牛逼啊!

這裡寫圖片描述

概述

在運用面向物件的思想進行軟體設計時,需要遵循的原則一共有7個,他們是:

1. 單一職責原則(Single Responsibility Principle)

每一個類應該專注於做一件事情。

2. 里氏替換原則(Liskov Substitution Principle)

超類存在的地方,子類是可以替換的。

3. 依賴倒置原則(Dependence Inversion Principle)

實現儘量依賴抽象,不依賴具體實現。

4. 介面隔離原則(Interface Segregation Principle)

應當為客戶端提供儘可能小的單獨的介面,而不是提供大的總的介面。

5. 迪米特法則(Law Of Demeter)

又叫最少知識原則,一個軟體實體應當儘可能少的與其他實體發生相互作用。

6. 開閉原則(Open Close Principle)

面向擴充套件開放,面向修改關閉。

7. 組合/聚合複用原則(Composite/Aggregate Reuse Principle CARP)

儘量使用合成/聚合達到複用,儘量少用繼承。原則: 一個類中有另一個類的物件。

細則

單一職責原則(Single Responsibility Principle)

因為:

可以降低類的複雜度,一個類只負責一項職責,其邏輯肯定要比負責多項職責簡單的多;提高類的可讀性,提高系統的可維護性;變更引起的風險降低,變更是必然的,如果單一職責原則遵守的好,當修改一個功能時,可以顯著降低對其他功能的影響。需要說明的一點是單一職責原則不只是面向物件程式設計思想所特有的,只要是模組化的程式設計,都適用單一職責原則。

所以:

從大局上看Android中的Paint和Canvas等類都遵守單一職責原則,Paint和Canvas各司其職。

里氏替換原則(Liskov Substitution Principle)

因為:

里氏替換原則告訴我們,在軟體中將一個基類物件替換成它的子類物件,程式將不會產生任何錯誤和異常,反過來則不成立,如果一個軟體實體使用的是一個子類物件的話,那麼它不一定能夠使用基類物件。里氏替換原則是實現開閉原則的重要方式之一,由於使用基類物件的地方都可以使用子類物件,因此在程式中儘量使用基類型別來對物件進行定義,而在執行時再確定其子類型別,用子類物件來替換父類物件。

所以:

使用里氏替換原則時需要注意,子類的所有方法必須在父類中宣告,或子類必須實現父類中宣告的所有方法。儘量把父類設計為抽象類或者介面,讓子類繼承父類或實現父介面,並實現在父類中宣告的方法,執行時,子類例項替換父類例項,我們可以很方便地擴充套件系統的功能,同時無須修改原有子類的程式碼,增加新的功能可以通過增加一個新的子類來實現。

從大局看Java的多型就屬於這個原則。

依賴倒置原則(Dependence Inversion Principle)

因為:

具體依賴抽象,上層依賴下層。假設B是較A低的模組,但B需要使用到A的功能,這個時候,B不應當直接使用A中的具體類;而應當由B定義一抽象介面,並由A來實現這個抽象介面,B只使用這個抽象介面;這樣就達到了依賴倒置的目的,B也解除了對A的依賴,反過來是A依賴於B定義的抽象介面。通過上層模組難以避免依賴下層模組,假如B也直接依賴A的實現,那麼就可能造成迴圈依賴。

所以:

採用依賴倒置原則可以減少類間的耦合性,提高系統的穩定性,減少並行開發引起的風險,提高程式碼的可讀性和可維護性。

從大局看Java的多型就屬於這個原則。

介面隔離原則(Interface Segregation Principle)

因為:

提供儘可能小的單獨介面,而不要提供大的總介面。暴露行為讓後面的實現類知道的越少越好。譬如類ProgramMonkey通過介面CodeInterface依賴類CodeC,類ProgramMaster通過介面CodeInterface依賴類CodeAndroid,如果介面CodeInterface對於類ProgramMonkey和類CodeC來說不是最小介面,則類CodeC和類CodeAndroid必須去實現他們不需要的方法。將臃腫的介面CodeInterface拆分為獨立的幾個介面,類ProgramMonkey和類ProgramMaster分別與他們需要的介面建立依賴關係。也就是採用介面隔離原則。

所以:

建立單一介面,不要建立龐大的介面,儘量細化介面,介面中的方法儘量少。也就是要為各個類建立專用的介面,而不要試圖去建立一個很龐大的介面供所有依賴它的類去呼叫。依賴幾個專用的介面要比依賴一個綜合的介面更靈活。介面是設計時對外部設定的約定,通過分散定義多個介面,可以預防外來變更的擴散,提高系統的靈活性和可維護性。

從大局來說Java的介面可以實現多繼承就是介面隔離原則的基礎保障。

迪米特法則(Law Of Demeter)

因為:

類與類之間的關係越密切,耦合度也就越來越大,只有儘量降低類與類之間的耦合才符合設計模式;對於被依賴的類來說,無論邏輯多複雜都要儘量封裝在類的內部;每個物件都會與其他物件有耦合關係,我們稱出現成員變數、方法引數、方法返回值中的類為直接的耦合依賴,而出現在區域性變數中的類則不是直接耦合依賴,也就是說,不是直接耦合依賴的類最好不要作為區域性變數的形式出現在類的內部。

所以:

一個物件對另一個物件知道的越少越好,即一個軟體實體應當儘可能少的與其他實體發生相互作用,在一個類裡能少用多少其他類就少用多少,尤其是區域性變數的依賴類,能省略儘量省略。同時如果兩個類不必彼此直接通訊,那麼這兩個類就不應當發生直接的相互作用。如果其中一個類需要呼叫另一個類的某一方法的話,可以通過第三者轉發這個呼叫。

從大局來說Android App開發中的多Fragment與依賴的Activity間互動通訊遵守了這一法則。

開閉原則(Open Close Principle)

因為:

開放封閉原則主要體現在對擴充套件開放、對修改封閉,意味著有新的需求或變化時,可以對現有程式碼進行擴充套件,以適應新的情況。軟體需求總是變化的,世界上沒有一個軟體的是不變的,因此對軟體設計人員來說,必須在不需要對原有系統進行修改的情況下,實現靈活的系統擴充套件。

所以:

可以通過Template Method模式和Strategy模式進行重構,實現對修改封閉,對擴充套件開放的設計思路。
封裝變化,是實現開放封閉原則的重要手段,對於經常發生變化的狀態,一般將其封裝為一個抽象,拒絕濫用抽象,只將經常變化的部分進行抽象。

組合/聚合複用原則(Composite/Aggregate Reuse Principle CARP)

因為:

其實整個設計模式就是在講如何類與類之間的組合/聚合。在一個新的物件裡面通過關聯關係(包括組合關係和聚合關係)使用一些已有的物件,使之成為新物件的一部分,新物件通過委派呼叫已有物件的方法達到複用其已有功能的目的。也就是,要儘量使用類的合成複用,儘量不要使用繼承。

如果為了複用,便使用繼承的方式將兩個不相干的類聯絡在一起,違反里氏代換原則,哪是生搬硬套,忽略了繼承了缺點。繼承複用破壞資料封裝性,將基類的實現細節全部暴露給了派生類,基類的內部細節常常對派生類是透明的,白箱複用;雖然簡單,但不安全,不能在程式的執行過程中隨便改變;基類的實現發生了改變,派生類的實現也不得不改變;從基類繼承而來的派生類是靜態的,不可能在執行時間內發生改變,因此沒有足夠的靈活性。

所以:

組合/聚合複用原則可以使系統更加靈活,類與類之間的耦合度降低,一個類的變化對其他類造成的影響相對較少,因此一般首選使用組合/聚合來實現複用;其次才考慮繼承,在使用繼承時,需要嚴格遵循里氏代換原則,有效使用繼承會有助於對問題的理解,降低複雜度,而濫用繼承反而會增加系統構建和維護的難度以及系統的複雜度,因此需要慎重使用繼承複用。

總結

至此,七大基本原則介紹完畢,很空洞,需要聯絡Java與android程式碼去仔細體會琢磨。