設計模式六大原則(PHP)

  設計模式的目的是爲了更好的代碼重用性,可讀性,可靠性和可維護性。經常使用的六大設計模式有:單一職責原則(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分別與他們須要的接口創建依賴關係。這就是接口隔離原則。舉個栗子:



能夠看出,接口中出現的方法,無論對依賴於它的類有沒有做用,實現類都必須實現這些方法。這個時候咱們把接口拆分下,實現接口隔離原則。舉個栗子:

看到這裏,你們可能會以爲接口隔離原則和單一職責原則很類似。其實不是的,1.單一職責原則是注重的這個類的職責,而接口隔離原則注重對接口依賴的隔離2.單一職責約束的是類,其次是方法,針對的是程序中的實現和細節,而接口隔離原則約束的是接口,是抽象,是程序框架總體的構建。

5.迪米特原則(Law of Demeter,也稱爲最少知識原則Least Knowledge Principle)

一個對象應該對其餘對象保持最少的瞭解。類與類之間的關係越密切,耦合度越大。迪米特原則又叫最少知道原則,即一個類對本身依賴的類知道的越少越好。也就是說,不管被依賴的類多麼複雜,都儘可能將邏輯封裝在類的內部。對外只提供public方法,而不對外泄露任何信息。迪米特原則還有個更簡單的定義:只與直接的朋友通訊。什麼是直接的朋友:每一個對象都會與其餘對象有耦合關係,只要兩個對象之間有耦合關係,咱們就稱這兩個對象之間是朋友關係。耦合的方式不少,依賴,關聯,組合,聚合等。其中,咱們稱出現成員變量,方法參數,方法返回值中的類爲直接的朋友,而出如今局部變量中的類不是直接的朋友。也就是說,陌生的類最好不要以局部變量的形式出如今類的內部。舉個栗子:

這個設計的問題在於CompanyManager中,SubCompanyManager類並非它的直接朋友。按照迪米特法則,應該避免類中出現這樣非直接朋友關係的耦合。修改以下

迪米特法則下降類之間的耦合,讓每一個類都減小了沒必要要的依賴;可是過分使用迪米特法則會產生大量的中介類和傳遞類,致使系統複雜度變大。因此在採用迪米特法則的時候要反覆權衡,既要作到結構清晰,同時作到高內聚低耦合。

開閉原則(Open Close Principle)

一個 軟件實體如類,模塊和函數應該對擴展開放,對修改關閉。用抽象構建框架,用實現擴展細節。當軟件須要變化時,儘可能經過擴展軟件實體的行爲來實現變化,而不是經過修改已有的代碼來實現變化。當咱們遵循前面介紹的五大原則,以及使用23種設計模式的目的就是遵循開閉原則。簡單的理解就是構建框架的時候要保持足夠的擴展性,通擴展來實現修改代碼而不是直接修改代碼。

相關文章
相關標籤/搜索