1. 程式人生 > >23-Python與設計模式--設計原則

23-Python與設計模式--設計原則

一 六大設計原則

在法理學中,法律規則與法律原則都是法律規範的重要構成。但二者也會有些不同:法律規則是指採取一定的結構形式具體規定人們的法律權利、法律義務以及相應的法律後果的行為規範,內容比較明確,比如,交通法規中規定,禁止闖紅燈;法律原則是指在一定法律體系中作為法律規則的指導思想,基本或本原的、綜合的、穩定的原理和準則,內容上只包含“大方針”,而並未有具體規則,比如,如果車上有馬上臨產的孕婦,闖紅燈不會被處罰,這是符合重視生命的原則。設計模式與設計原則,基本符合規則與原則的關係,設計模式是一個個具體問題的解決方案,設計原則則反映了這些設計模式的指導思想;同時,設計原則可衍生出的設計模式也不僅限於上述介紹到了23種設計模式,任何一種針對特定業務場景中的解決方法,雖然找不到對應的設計模式與之匹配,但若符合設計原則,也可以認為是一種全新的設計模式。從這個意義上來說,設計模式是程式設計方法的形,而設計原則是程式設計方法的神。

1、單一職責原則

單一職責原則英文原名為Single Responsibility Principle,簡稱SRP原則。其含義為:應該有且僅有一個原因引起類的變更。舉個例子來說明單一職責原則:一個視訊播放系統,一個客戶端類有兩個功能介面,即視訊播放介面和音訊播放介面。雖然這樣的設計很常見,但卻不滿足單一職責原則的。原因是,如果對視訊播放有變更需求或者對音訊播放有修改需求,都會變更視訊客戶端的類結構。符合單一原則的設計是,將視訊播放單元和音訊播放單元各建一個類,播放客戶端繼承兩個類,構成客戶端。
單一職責原則的最大難點在於職責的劃分,試想,以上劃分是否是符合單一職責了?既是,也不是。試想,如果將視訊傳輸和音訊傳輸的協議資訊和資料資訊區分開,為符合這種粒度的單一職責原則就必須要有協議傳輸類和資料傳輸類的劃分。如果接著細分,可能一個簡單的小模組,都要設計非常多的類。因此,單一職責原則粒度的選擇,應該根據業務流程和人員分工來進行考慮。一些基本的劃分,似乎已經成了行業規範性的內容,比如,業務邏輯與使用者資訊管理的劃分等。

2、里氏替換原則

里氏替換原則英文原名為Liskov Substitution Principle,簡稱LSP原則。它是面向物件設計的最為基本原則之一。 里氏替換原則的含義為:任何基類可以出現的地方,子類一定可以出現。 LSP是繼承複用的基石,只有當子類可以替換掉基類,軟體單位的功能不受到影響時,基類才能真正被複用,子類也能夠在基類的基礎上增加新的行為。舉例說明:對於一個鳥類,可以衍生出麻雀、喜鵲、布穀等子類,這些子類都可繼承鳥類的鳴叫、飛行、吃食等介面。而對於一個雞類,雖然它在生物學上屬於鳥類,但它不會飛,那麼符合LSP設計原則的情況下,雞就不應該是鳥的一個子類:在鳥類呼叫飛行介面的地方,雞類並不能出現。如果雞類要使用鳥類的介面,應該使用關聯關係,而不是繼承關係。

3、依賴倒置原則

依賴倒置原則英文原名為Dependence Inversion Principle,簡稱DIP原則。它的含義為:高層模組不應該依賴於低層模組,兩者都應該依賴其抽象。抽象不應該依賴於細節,細節應該依賴於抽象。我們將每個不可細分的邏輯叫作原子邏輯,原子邏輯組裝,形成低層模組,低層模組組裝形成高層模組。依賴倒置原則的含義為,高層模組和低層模組都應該由各自的抽象模組派生而來,同時介面設計應該依賴於抽象,而非具體模組。舉個例子:司機與汽車是依賴的關係,司機可以有實習司機類、老司機類等派生;汽車可以有轎車、SUV、卡車等派生類。如果司機中設計一個介面drive,汽車是其引數,符合DIP設計原則的引數,應該是在基類司機類中,將基類汽車類作為引數,而司機的派生類中,drive的引數同樣應該為基類汽車類,而不應該是汽車類的任一個派生類。如果規定實習司機只能開轎車等業務邏輯,應該在其介面中進行判斷,而不應該將引數替換成子類轎車。

4、介面隔離原則

介面隔離原則英文原名為Interface Segregation Principle,簡稱ISP原則。其含義為:類間的依賴關係不應該建立一個大的介面,而應該建立其最小的介面,即客戶端不應該依賴那些它不需要的介面。這裡的介面的概念是非常重要的。從邏輯上來講,這裡的介面可以指一些屬性和方法的集合;從業務上來講,介面就可以指特定業務下的介面(如函式,URL呼叫等)。介面應該儘量小,同時僅留給客戶端必要的介面,棄用沒有必要的介面。舉例說明:如果要根據具體的資料,生成餅圖、直方圖、表格,這個類該如何設計?如果將生成餅圖、直方圖、表格等“介面”(這裡的介面就是“操作”的集合的概念),寫在一個類中,是不符合介面隔離原則的。符合ISP原則的設計應該是設計三個類,每個類分別實現餅圖、直方圖、表格的繪製。
介面隔離原則和單一職責原則一樣,涉及到粒度的問題,解決粒度大小,同樣依賴於具體的業務場景,需要讀者根據實踐去權衡。

5、迪米特法則(最少知識原則)

迪米特法則(Law of Demeter)也叫最少知識原則,英文Least Knowledge Principle,簡稱LKP原則。其含義為:一個物件應該對其它物件有最少的瞭解。舉例說明:一個公司有多個部門,每個部門有多個員工,如果公司CEO要下發通知給每個員工,是呼叫介面直接通知所有員工麼?其實不然,CEO只需和它的“朋友”類部門Leader交流就好,部門Leader再下發通知資訊即可。而CEO類不需要與員工進行“交流”。
迪米特法則要求物件應該僅對自己的朋友類交流,而不應該對非朋友類交流。那什麼才是朋友類呢?一般來說,朋友類具有以下特徵:
1)當前物件本身(self);
2)以參量形式傳入到當前物件方法中的物件;
3)當前物件的例項變數直接引用的物件;
4)當前物件的例項變數如果是一個聚集,那麼聚集中的元素也都是朋友;
5)當前物件所建立的物件。

6、開閉原則

開閉原則英文原名為Open Closed Principle,簡稱OCP原則。其含義為:一個軟體實體,如類、模組、函式等,應該對擴充套件開放,對修改關閉。開閉原則是非常基礎的一個原則,也有人把開閉原則稱為“原則的原則”。前面講到過,模組分原子模組,低層模組,高層模組,業務層可以認為是最高層次的模組。對擴充套件開放,意味著模組的行為是可以擴充套件的,當高層模組需求改變時,我們可以對低層模組進行擴充套件,使其具有滿足高層模組的新功能;對修改關閉,即對低層模組行為進行擴充套件時,不必改動模組的原始碼。最理想的情況是,業務變動時,僅修改業務程式碼,不修改依賴的模組(類、函式等)程式碼,通過擴充套件依賴的模組單元來實現業務變化。舉例說明:假設一個原始基類水果類,蘋果類是它的派生類,蘋果中包含水果的各種屬性,如形狀、顏色等;另有兩個類,農民類和花園類,最高層次(業務層次)為農民在花園種蘋果。如果此時,農民決定不種蘋果了,改種梨,符合OCP原則的設計應該為基於水果類構建一個新的類,即梨類(對擴充套件開放),而並不應該去修改蘋果類,使它成為一個梨類(對修改關閉)。修改應僅在最高層,即業務層中進行。

回到目錄

二 遵循設計原則的好處

由於設計原則是設計模式的提煉,因而設計原則的好處與設計模式是一致的,即:程式碼易於理解;更適於團體合作;適應需求變化等。

回到目錄

三、設計原則與設計模式

1、建立類設計模式與設計原則

工廠模式:工廠方法模式是一種解耦結構,工廠類只需要知道抽象產品類,符合最少知識原則(迪米特法則);同時符合依賴倒置原則和里氏替換原則;
抽象工廠模式:抽象工廠模式具有工廠模式的優點,但同時,如果產品族要擴充套件,工廠類也要修改,違反了開閉原則;
模板模式:優秀的擴充套件能力符合開閉原則。

2、結構類設計模式與設計原則

代理模式:代理模式在業務邏輯中將對主體物件的操作進行封裝,合適的應用會符合開閉原則和單一職責原則;事實上,幾乎帶有解耦作用的結構類設計模式都多少符合些開閉原則;
門面模式:門面模式不符合開閉原則,有時不符合單一職責原則,如若不注意,也會觸碰介面隔離原則;
組合模式:符合開閉原則,但由於一般在拼接樹時使用實現類,故不符合依賴倒置原則;
橋樑模式:橋樑模式堪稱依賴倒置原則的典範,同時也符合開閉原則。

3、行為類設計模式與設計原則

策略模式:符合開閉原則,但高層模組呼叫時,不符合迪米特法則。行為類設計模式多少會符合些單一職責原則,典型的如觀察者模式、中介者模式、訪問者模式等;
責任鏈模式:符合單一職責原則和迪米特法則;
命令模式:符合開閉原則。

在不同的業務邏輯中,不同的設計模式也會顯示出不同的設計原則特點,從這個意義上來說,設計模式是設計原則的體現,但體現不是固定的,是根據業務而有所不同的。