目錄
一、開放封閉原則
概念理解
開放封閉原則是指在進行物件導向設計中,設計類或者程式應該遵循兩點:對擴充套件開放和對修改關閉。這樣,乙個模組在實現的過程中,就可以在不修改原來的模組(修改關閉)基礎上,擴充套件器功能(擴充套件開放)。
開閉原則的實現方法
為了滿足開閉原則的對修改關閉,對擴充套件開放原則,應該對軟體系統中的不變的部分加以抽象。
實現原則:
優點:開閉原則的相對性
軟體系統的構建是乙個需要不斷重構的過程,在這個過程中,模組的功能抽象,模組與模組之間的關係,都不會從一開始就非常清晰明了。所以構建100%滿足開閉原則的軟體系統是非常困難的,這就是開閉原則的相對性。
但是在設計過程中,通過對模組功能的抽象(介面定義),模組之間的關係的抽象(通過介面呼叫),抽象與實現的分離(面向介面的程式設計)等,可以盡量接近滿足開閉原則。
二、裡式替換原則
所有引用父類的地方必須能夠透明地使用其子類的物件。
概念理解
只要父類能出現的地方子類就可以出現,而且替換為子類也不會產生任何錯誤或異常,使用者不需要知道是父類還是子類。但是,反過來就不行了,有子類出現的地方,父類未必就能適應。
滿足條件:
體現原則:
裡式替換原則為我們是否應該使用繼承提供了判斷的依據,不再是簡單地根據兩者之間是否有相同之處來決定是否使用繼承。
裡式替換原則的引申意義:子類可以擴充套件父類的功能,但是不能改變父類原有的功能。
表現幾點:
優點:
class示例重構違反lcp的設計:user:
defshow_name(self):
pass
classvipuser(user):
defshow_name(self):
pass
defshow_user(u):
res =u.show_name()
vipuser這個類繼承了user,它重寫了父類的show_name,這個時候就必須保證子類的show_name方法的引數和返回值。不然當使用show_user方法呼叫的時候會出現問題。
如果兩個具體的類a,b的關係違反了lsp的設計,(假設是從b到a的繼承關係),那麼根據具體的情況可以在下面的兩種重構方案中選擇一種:
在進行設計的時候,我們盡量從抽象類繼承,而不是從具體類繼承。
如果從繼承等級樹來看,所有葉子結點應該是具體類,而所有樹枝節點應該是抽象類或者介面。當然這只是乙個一般性的指導原則,使用的時候還要具體情況具體分析。
在很多情況下,在設計初期我們類之間的關係不是很明確,lsp則給了我們乙個判斷和設計類之間關係的基準:需不需要繼承,以及怎樣設計繼承關係。
三、依賴倒置原則
高層模組不應該依賴於底層模組,二者都應該依賴於抽象。
抽象不應該依賴於細節,細節應該依賴於抽象。
針對介面程式設計,不要針對實現程式設計。
概念理解
依賴:在程式設計中,如果乙個模組a呼叫了另乙個模組b,我們稱模組a依賴模組b。
高層模組和底層模組:在乙個應用程式中,我們有一些低層次的類,這些類實現了一些基本的或者初級的操作,我們稱之為底層模組,另外有一些高層次的類,這些類封裝了某些複雜的邏輯,並且依賴於低層次的類,這些類我們稱之為高層模組。
依賴倒置:物件導向程式設計相對於面向過程程式設計而言,依賴關係被倒置了。因為傳統的結構化程式設計中,高層模組總是依賴於底層模組。
問題提出:
robert c. martin在書中給出了bad design的幾個特徵:
這其中導致bad design的乙個很大的原因是高層模組過分依賴底層模組。
但是乙個良好的設計應該是系統的每個部分都是可替換的。如果高層模組過分依賴底層模組,一方面一旦底層模組需要替換或者修改,高層模組將受到影響,另外一方面,高層模組很難可以重用。
問題的解決:
robert c. martin提出了dependency inversion principle (dip) 原則。
dip給出了乙個解決方案:在高層模組與底層模組之間,引入乙個抽象介面層。
high level classes(高層模組) --> abstraction layer(抽象介面層) --> low level classes(低層模組)。
抽象介面是對底層模組的抽象,低層模組繼承或者實現該抽象介面。
這樣高層模組不直接依賴低層模組,而是依賴抽象介面層。抽象介面也不依賴低層模組的實現細節,而是低層模組依賴(繼承或實現)抽象介面。
類與類之間都是通過抽象介面層來建立關係的。
怎麼使用依賴倒置原則
1、依賴於抽象
2、設計介面而非設計實現
例外:有些類不可能變化,在可以直接使用具體類的情況下,不需要插入抽象層,如字串。
3、避免傳遞依賴
優點:四、介面隔離原則
不能強迫使用者依賴那些它們不適用的介面。
概念理解
換句話說,使用多個專門的介面比使用單一的總介面要好。
介面隔離原則指導我們:
下面我們舉例說明怎麼設計介面或類之間的關係,使其不違反isp原則。
假如有乙個door,有lock,unlock功能,另外,可以在door上安裝乙個alarm而使其具有報警功能。使用者可以選擇一般的door,也可以選擇具有報警功能的door。
isp原則的違反例一:在door介面裡定義所有的方法。
但這樣一來,依賴door介面的commondoor卻不得不實現未使用的alarm()方法。違反了isp原則。
isp原則的違反例二:在alarm介面定義alarm方法,在door介面定義lock,unlock方法,door介面繼承alarm介面。
跟方法一一樣,依賴door介面的commondoor卻不得不實現未使用的alarm()方法。違反了isp原則。
遵循isp原則的例一:通過多重繼承實現
在alarm介面定義alarm方法,在door介面定義lock,unlock方法。介面之間無繼承關係。commondoor實現door介面,alarmdoor有2種實現方案:
1)同時實現door和alarm介面。
2)繼承commondoor,並實現alarm介面。
第2)種方案更具有實用性。
這樣的設計遵循了isp設計原則。
遵循isp原則的例二:通過關聯(或者叫做組合)實現
在這種方法裡,alarmdoor實現了alarm介面,同時把功能lock和unlock委讓給commondoor物件完成。
這種設計遵循了isp設計原則。
介面分隔原則的優點和適度原則
五、單一職責原則
如果乙個類需要改變,改變它的理由永遠只有乙個。如果存在多個改變它的理由,就需要重新設計該類。也就乙個類只做一件事。
只能讓乙個類/介面/方法有且僅有乙個職責。
如果乙個類具有乙個以上的職責,那麼就會有多個不同的原因引起該類變化,而這種變化將影響到該類不同職責的使用者(不同使用者):
這違反了設計的開閉原則,也不是我們所期望的。
物件導向設計原則
oo原則 封裝變化 多用組合,少用繼承 針對介面程式設計,不針對實現程式設計 為互動物件之間的松耦合而努力 類應該對擴充套件開放,對修改關閉 依賴抽象,不要依賴具體類 只和朋友交談 別找我,我會找你 類應該只有乙個改變的理由 從設計原則到設計模式 針對介面程式設計,而不是針對實現程式設計 客戶無需知...
物件導向設計原則
物件設計原則 物件導向設計原則 物件導向設計的基石是 開 閉 原則。開一閉 原則講的是 乙個軟體實體應當對擴充套件開放,對修改關閉。這個規則說的是,在設計乙個模組的時候,應當使這個模組可以在不被修改的前提下被擴充套件。從另外乙個角度講,就是所謂的 對可變性封裝原則 對可變性封裝原則 意味著兩點 1 ...
物件導向設計原則
oo原則 封裝變化 多用組合,少用繼承 針對介面程式設計,不針對實現程式設計 為互動物件之間的松耦合而努力 類應該對擴充套件開放,對修改關閉 依賴抽象,不要依賴具體類 只和朋友交談 別找我,我會找你 類應該只有乙個改變的理由 從設計原則到設計模式 針對介面程式設計,而不是針對實現程式設計 客戶無需知...