設計模式的目的是爲了更好的代碼重用性,可讀性,可靠性和可維護性。常用的六大設計模式有:單一職責原則(SRP),里氏替換原則(LSP),依賴倒轉原則(DIP),接口隔離原則(ISP),迪米特法則(LOD),開閉原則(OCP)。
1.單一職責原則(Single Responsibility Principle)
該原則是針對類來說的,即一個類應該只負責一項職責。假設有一個部門的類叫做T,他的下面有兩個職責的方法叫做P1,P2。假如P1的職責發生改變時去修改這個部門類T,那麼有可能造成職責P2發生故障。
舉個栗子:
我們用動物呼吸的場景來表現一下
輸出結果:
但是呢,我們發現並不是所有的動物都是呼吸空氣的,比如說魚它是呼吸水的。根據SRP原則,我們應該將Animal類分爲陸地動物和海洋生物,如下所示:
但是我們發現這樣修改花銷很大,既要將原來的類分解,又要修改客戶端。而直接修改Animal類則違背了單一職責原則,但花銷很小 如下所示:
這種修改方式沒有改變原來的方法,而是在類中新加了一個方法,這樣雖然違反了單一職責原則,但是在方法級別上卻是符合單一職責原則的。在實際的編程中,只有邏輯足夠簡單,纔可能在代碼級違反單一職責原則;只有類中的方法數量足夠少,纔可以在方法級別上違反單一職責原則。
遵循單一職責的優點:
(1)降低類的複雜度,一個類只負責一項職責。
(2)提高類的可讀性,可維護性。
(1)降低變更引起的風險。
2.里氏替換原則(Liskov Substitution Principle)
該原則提出,如果對每個類型爲T1的對象o1,都有類型爲T2的對象o2,使得以T1定義的所有程序P在所有的對象o1都代換成o2時,程序P的行爲沒有發生變化,那麼類型T2是類型T1的子類型。這話原句,不知道是翻譯的鍋還是咋地,看起來就晦澀難懂。其實可以簡單地理解爲所有引用基類的地方必須能夠透明的使用其子類的對象,在子類中儘量不要重寫和重載父類的方法。
繼承作爲面向對象的三大特性之一,在給程序帶來巨大便利的同時,也帶來了弊端。比如繼承會給程序帶來可入侵行,程序的可移植性降低,增加了對象間的耦合性。如果一個類被其他類所繼承,那麼這個類在被修改的時候,必須考慮到所有的子類。並且父類在修改後,所以涉及到子類的功能都有可能發生故障。
舉個栗子:
運行結果:
後來呢,我們想做個功能,將兩個數相加並且乘以100.這個時候我們看到上面那個類也是兩個參數,只不過是相減。我們繼承一下A重寫下那個方法不就完成求和再求積嗎?代碼如下:
運行結果:
結果我們發現,在業務邏輯代碼沒變的情況下結果居然跟預期的結果不一樣了。因爲C類雖然繼承了A類,但是它重寫了A類的subtract方法,造成了原有功能的錯誤。在實際的編碼過程中我們通常會重寫父類的方法來完成新的功能,但是這樣會使得類的繼承體系複用性特別差。這個時候我們可以選擇讓A和C共同繼承一個更通俗的基類,然後實現他的方法,去掉A和C的繼承關係,採用依賴、聚合、組合等關係代替。舉個栗子:
這樣我們既可以保持原有的業務關係,又可以實現更多的功能。
3.依賴倒轉原則(Dependence Inversion Principle)
依賴倒置規定:高層模塊不應該依賴於低層模塊,二者都應該依賴其抽象;抽象不應該依賴於細節,細節應該依賴於抽象。因爲相對於細節的多變性,抽象的東西要穩定的多。以抽象爲基礎搭建的架構要比以細節爲基礎的架構要穩定的多。依賴倒置的中心思想是面向接口編程。上層模塊不應該依賴於下層模塊,應該依賴於接口。從而使得下層模塊依賴於上層的接口,降低耦合度,提高系統的彈性。這六大原則是最虛,最抽象的,很難理解。舉個栗子說明:
但是如果我們讀的是報紙,雜誌呢,發現book並不適用了。我們引入一個抽象的接口IReader,代表讀物。讓Mother類與接口IReader發生依賴關係,而Book和Newspaper都屬於讀物的範疇,讓他們各自都去實現IReader接口,這樣就符合高層不應該依賴低層,應該依賴於接口的依賴倒置原則,修改後代碼如下:
用了依賴倒置原則之後會發現帶給我們極大的便利,比如例子,一開始Mother類與Book類耦合,如果要修改讀物的話,必須要創建一個新的讀物類,然後修改Mother類中傳入的類名,非常的麻煩。而修改後Mother類則直接依賴了IReader接口,這樣與Book解耦,每次只需要創建一個新的讀物類實現IReader接口即可調用
依賴關係的傳遞有三種辦法,分別是接口傳遞、構造方法傳遞以及setter方法傳遞。
1.接口傳遞
2.構造方法傳入(常用)
3.setter方法傳遞
在實際的編程中儘量注意以下三點:1.低層模塊儘量都要有抽象類或者接口類,或者兩者都有2.變量的聲明類型儘量是抽象類或者接口(這裏是指傳入的那個變量代表的類)3.遵循里氏替換原則。控制反轉(IOC)和依賴注入(DI)也是基於此原則,把所有類的實例化放在了一個容器中,從容器中獲取調用,降低了高層類對低層類的依賴。有學習IOC和DI的,可以留個郵箱,我會把一些理解的例子發一下。
4.接口隔離原則(InterfaceSegregation Principles)
一個類不應該依賴他不需要的接口;一個類對另一個類的依賴應該建立在最小接口上。比如類A通過接口E依賴類B,類C通過接口E依賴類D,如果接口E對於類A和類C來說不是最小接口的話,則類B和類D必須去實現他們不需要的方法。這個時候我們將臃腫的接口拆分成獨立的幾個接口,類A和類C分別與他們需要的接口建立依賴關係。這就是接口隔離原則。舉個栗子: