天天看點

23、Python與設計模式--設計原則一、六大設計原則二、遵循設計原則的好處三、設計原則與設計模式

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

單一職責原則英文原名為single responsibility principle,簡稱srp原則。其含義為:應該有且僅有一個原因引起類的變更。舉個例子來說明單一職責原則:一個視訊播放系統,一個用戶端類有兩個功能接口,即視訊播放接口和音頻播放接口。雖然這樣的設計很常見,但卻不滿足單一職責原則的。原因是,如果對視訊播放有變更需求或者對音頻播放有修改需求,都會變更視訊用戶端的類結構。符合單一原則的設計是,将視訊播放單元和音頻播放單元各建一個類,播放用戶端繼承兩個類,構成用戶端。

單一職責原則的最大難點在于職責的劃分,試想,以上劃分是否是符合單一職責了?既是,也不是。試想,如果将視訊傳輸和音頻傳輸的協定資訊和資料資訊區分開,為符合這種粒度的單一職責原則就必須要有協定傳輸類和資料傳輸類的劃分。如果接着細分,可能一個簡單的小子產品,都要設計非常多的類。是以,單一職責原則粒度的選擇,應該根據業務流程和人員分工來進行考慮。一些基本的劃分,似乎已經成了行業規範性的内容,比如,業務邏輯與使用者資訊管理的劃分等。

裡氏替換原則英文原名為liskov substitution principle,簡稱lsp原則。它是面向對象設計的最為基本原則之一。 裡氏替換原則的含義為:任何基類可以出現的地方,子類一定可以出現。 lsp是繼承複用的基石,隻有當子類可以替換掉基類,軟體機關的功能不受到影響時,基類才能真正被複用,子類也能夠在基類的基礎上增加新的行為。舉例說明:對于一個鳥類,可以衍生出麻雀、喜鵲、布谷等子類,這些子類都可繼承鳥類的鳴叫、飛行、吃食等接口。而對于一個雞類,雖然它在生物學上屬于鳥類,但它不會飛,那麼符合lsp設計原則的情況下,雞就不應該是鳥的一個子類:在鳥類調用飛行接口的地方,雞類并不能出現。如果雞類要使用鳥類的接口,應該使用關聯關系,而不是繼承關系。

依賴倒置原則英文原名為dependence inversion principle,簡稱dip原則。它的含義為:高層子產品不應該依賴于低層子產品,兩者都應該依賴其抽象。抽象不應該依賴于細節,細節應該依賴于抽象。我們将每個不可細分的邏輯叫作原子邏輯,原子邏輯組裝,形成低層子產品,低層子產品組裝形成高層子產品。依賴倒置原則的含義為,高層子產品和低層子產品都應該由各自的抽象子產品派生而來,同時接口設計應該依賴于抽象,而非具體子產品。舉個例子:司機與汽車是依賴的關系,司機可以有實習司機類、老司機類等派生;汽車可以有轎車、suv、卡車等派生類。如果司機中設計一個接口drive,汽車是其參數,符合dip設計原則的參數,應該是在基類司機類中,将基類汽車類作為參數,而司機的派生類中,drive的參數同樣應該為基類汽車類,而不應該是汽車類的任一個派生類。如果規定實習司機隻能開轎車等業務邏輯,應該在其接口中進行判斷,而不應該将參數替換成子類轎車。

接口隔離原則英文原名為interface segregation principle,簡稱isp原則。其含義為:類間的依賴關系不應該建立一個大的接口,而應該建立其最小的接口,即用戶端不應該依賴那些它不需要的接口。這裡的接口的概念是非常重要的。從邏輯上來講,這裡的接口可以指一些屬性和方法的集合;從業務上來講,接口就可以指特定業務下的接口(如函數,url調用等)。接口應該盡量小,同時僅留給用戶端必要的接口,棄用沒有必要的接口。舉例說明:如果要根據具體的資料,生成餅圖、直方圖、表格,這個類該如何設計?如果将生成餅圖、直方圖、表格等“接口”(這裡的接口就是“操作”的集合的概念),寫在一個類中,是不符合接口隔離原則的。符合isp原則的設計應該是設計三個類,每個類分别實作餅圖、直方圖、表格的繪制。

接口隔離原則和單一職責原則一樣,涉及到粒度的問題,解決粒度大小,同樣依賴于具體的業務場景,需要讀者根據實踐去權衡。

迪米特法則(law of demeter)也叫最少知識原則,英文least knowledge principle,簡稱lkp原則。其含義為:一個對象應該對其它對象有最少的了解。舉例說明:一個公司有多個部門,每個部門有多個員工,如果公司ceo要下發通知給每個員工,是調用接口直接通知所有員工麼?其實不然,ceo隻需和它的“朋友”類部門leader交流就好,部門leader再下發通知資訊即可。而ceo類不需要與員工進行“交流”。

迪米特法則要求對象應該僅對自己的朋友類交流,而不應該對非朋友類交流。那什麼才是朋友類呢?一般來說,朋友類具有以下特征:

1)目前對象本身(self);

2)以參量形式傳入到目前對象方法中的對象;

3)目前對象的執行個體變量直接引用的對象;

4)目前對象的執行個體變量如果是一個聚集,那麼聚集中的元素也都是朋友;

5)目前對象所建立的對象。

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

由于設計原則是設計模式的提煉,因而設計原則的好處與設計模式是一緻的,即:代碼易于了解;更适于團體合作;适應需求變化等。

工廠模式:工廠方法模式是一種解耦結構,工廠類隻需要知道抽象産品類,符合最少知識原則(迪米特法則);同時符合依賴倒置原則和裡氏替換原則;

抽象工廠模式:抽象工廠模式具有工廠模式的優點,但同時,如果産品族要擴充,工廠類也要修改,違反了開閉原則;

模闆模式:優秀的擴充能力符合開閉原則。

代理模式:代理模式在業務邏輯中将對主體對象的操作進行封裝,合适的應用會符合開閉原則和單一職責原則;事實上,幾乎帶有解耦作用的結構類設計模式都多少符合些開閉原則;

門面模式:門面模式不符合開閉原則,有時不符合單一職責原則,如若不注意,也會觸碰接口隔離原則;

組合模式:符合開閉原則,但由于一般在拼接樹時使用實作類,故不符合依賴倒置原則;

橋梁模式:橋梁模式堪稱依賴倒置原則的典範,同時也符合開閉原則。

政策模式:符合開閉原則,但高層子產品調用時,不符合迪米特法則。行為類設計模式多少會符合些單一職責原則,典型的如觀察者模式、中介者模式、通路者模式等;

責任鍊模式:符合單一職責原則和迪米特法則;

指令模式:符合開閉原則。

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