任何變量都不應該持有一個指向具體類的指針或引用;
"你不必嚴格遵守這些原則,違背它們也不會被處以宗教刑罰.
但你應當把這些原則看成警鈴,若違背了其中的一條,那麼警鈴就會響起."
(就一個類而言,應該僅有一個引起它變化的原因.)
詳細說明:
如果一個類承擔的職責過多,就等於把這些職責耦合在一起.
一個職責的變化可能會削弱或者抑制這個類完成其它職責的能力.
這種耦合會導致脆弱的設計,當變化發生時,設計會遭受到意想不到的破壞.
結論:
它是所有類設計原則最簡單的,也是最難正確使用的.
我們會自然的把職責結合在一起,軟件設計真正要做的內容就是發現職責並把那些職責相互分離.
(軟件實體(類,模塊,函數...)應該是可以擴展的,但是不可以修改.)
詳細說明:
OCP=對於擴展是開放的,對於修改是封閉的.
如果程序中的一處改動就會產生連鎖反應,導致一系列相關模塊的改動,那麼設計就有臭味.
OCP建議我們如果要對系統進行重構,就只需要添加新的代碼,而不必改動已經正常運行的代碼.
結論:
在許多方面,OCP都是面向對象設計的核心.
尊循它可以帶來巨大的好處(程序的靈活性,可重用性,可維護性).
在代碼中肆意使用OCP也不是一個好主意.
正確的做法是:開發人員僅僅對程序中呈現頻繁變化的部分做出抽象!拒絕不成熟的抽象和抽象本身一樣重要!
3.LSP Liskov替換原則[適用於類層次]
(子類型必須能夠替換掉它們的基類型.)
詳細說明:
Barbara Liskov在1988年說道:
Liskov替換性質:若對每個類型S的對象O1,都存在一個類型T的對象O2,
在所有針對類型T編寫的程序P中,用O1代換O2後,程序P行爲功能不變,則類型S是類型T的子對象.
結論:
LSP是使用OCP開放-封閉原則成爲可能的主要原則之一,
正是子類型的可替換性才能用基類類型(基類引用或者指針)的模塊在無需修改的情況下就可以擴展.
這種可替換性是開發人員可以隱式依賴的東西.
因此,如果沒有顯示的強制基類類型的契約,那麼代碼就必須良好並明顯的表達出這一點.
術語"IS-A"不能作爲子類型的定義,
子類型的正確定義是"可替換性","可替換性"可以通過顯式或者隱式的(動態綁定必須用基類類型)契約.
4.DIP依賴倒置原則[適用於類層次]
(抽象不應該依賴細節.細節應該依賴抽象.)
詳細說明:
a.高層模塊不應該依賴於低層模塊,二者都應該依賴抽象(使用接口或者虛類來連接).
b.抽象不應該依賴於細節,細節應該依賴於抽象.
結論:
使用傳統的過程化程序設計方法所創建出來的依賴關係結構和策略是依賴於細節.
DIP使得細節和策略都依賴於抽象,並且常常爲客戶定製服務接口.
事實上,這種依賴關係的倒置是好的面向對象的程序設計的標記.
DIP正確應用對於可重用框架是必須的,對於構建在變化面前富有彈性的代碼也是非常重要的.
由於抽象和細節被DIP彼此隔離,所以代碼也非常容易維護.
5.ISP接口隔離原則[適用於類的接口]
不應該強迫客戶程序依賴於它們不用的方法.
接口屬於客戶,不屬於它所在的類層次結構.
詳細說明:
分離客戶就是分離接口.分離接口有2種方法:委託和多重繼承
接口隔離原則是用來處理胖接口所具有的缺點.
如果類接口不是內聚的,就表示該類的接口是胖的,需要減肥.
減肥的原則是接口分成多組方法,每一組方法都服務於一組不同的客戶程序!
客戶程序面對的就是多個具有內聚接口的抽象基類.
胖類會導致它們的客戶程序之間產生不正常的有害的耦合關係.
當客戶程序要求胖類進行一個改動時,會影響到所有其它戶程序.
因此,程序應該僅僅依賴於它們實際調用的方法.
通過把胖類的接口分解爲多個特定的客戶程序的接口,可以實現這個目標.
每個特定於客戶程序的接口僅僅聲明它自己調用的函數.
解除了類的客戶程序之間依賴關係,使它們互不依賴.
6.REP重用發佈等價原則[適用於包]
(重用的粒度就是發佈的粒度)
詳細說明:
當你重用別人一個類庫時,你的期望是什麼?
當然是好的文檔,可以工作的代碼,規格清晰的接口!
你希望作者會一直維護類庫代碼,當作者都把類庫的接口和功能進行任何改變時,你希望得到通知.
代碼的作者把它們的軟件組織到一個包中(dll,jar,...),所以我們重用的粒度就是包的發佈粒度.
結論:
一個包的重用粒度和和發佈粒度一樣大,由於重用性是基於包的,所以可重用的包必須包含可重用的類.
(包中的所有類對於同一類性質的變化應該是共同封閉的.
一個變化若對一個包產生影響,則將對該包中的所有類產生影響,而對於其它包不造成任何影響.)
詳細說明:
這是SRP單一職責原則對包的重新規定.這規定了一個包不應該包含多個引用包變化的原因.
在大多數應用中,可維護性超過可重用性.
代碼更改:如果代碼要更改,原意更改都集中在一個包中,而不是分佈於多個包中.
代碼發佈:我們也只發布更改中的包!
結論:
CCP鼓勵我們把可以由於同樣的原因而更改的所有類共同聚集在同一個包中.
(一個包中的所有類應該是共同重用的.
如果重用了包中的一個類,那麼就要重用包中的所有類.)
詳細說明:
一個包中的所有類應該是共同重用的.
結論:
如果重用了包中的一個類,那麼就要重用包中的所有類.
這個原則可以幫助我們決定哪些類應該放進同一個包中.
(在包的依賴關係圖中不允許存在環.)
詳細說明:
如果開發環境中有許多開發人員都在更改相同的源代碼文件集合的情況,
因爲有人比你走的晚,且改了你所依賴一些東西(類或者方法),第二天來上班,
你昨天完成的功能,今天不能正常工作,那麼就會發生"晨後綜合症"!
針對此問題有兩個解決方案:"每週構建"和"消除依賴環"
每週構建:應用於中等規模的項目中,它的工作方式爲:每週1-4,開發人員各自工作在私人的代碼空間,周5-6聯合調試!
消除依賴環:通過把開發環境劃分成可發佈的包,可以解決依賴環.
結論:
解決包之間的依賴環有兩個主要方法:
1.使用依賴倒置原則,在類和依賴類之前添加一個依賴的接口或者抽象類,解除依賴環.
2.添加新類,把類和依賴類之間的依賴移到一個新的類,解除依賴環.
10.SDP穩定依賴原則[適用於包]
(朝着穩定的方向進行依賴.)
詳細說明:
設計不是完全固定的,要使設計可維護,某種程序的易變性是必要的.
使用這個原則,我們可以創建對某些變化類型敏感的包.
軟件包就可以分爲穩定包和可變包!
如何識別穩定包和可變包?如果許多其它的包都依賴此包,那麼它就是穩定包,否則就是可變包!
把包放在不同的位置,它的穩定性是不同的.
如何計算一個包的不穩定性?(輸入耦合度Ca,輸出耦合度Ce)
不穩定值=Ce/(Ca+ce),此值越低越穩定!
結論:
把可變包不穩定值降低的方法是:爲它加上一個抽象外衣(interface/抽象類),其它包調用抽象外衣!
可變包爲抽象外衣的實現!
11.SAP穩定抽象原則[適用於包]
(包的抽象程序應該和其它穩定程序一致.)
詳細說明:
此原則把包的穩定性和抽象性聯繫到一起.
一個穩定的包應該是抽象的,這樣它的穩定性就不會使其無法擴展;
一個不穩定的包應該具體的, 這樣它的不穩定性使代碼易於修改.
它指出一個包有時候應該達到部分是可抽象的,部分是不穩定的原則