兩大主題
系統複用:如何使用已有的元件或類來構建新系統
系統擴充套件:如何透過擴充套件現有的系統,同時保持系統的可維護性和靈活性。
設計模式主要關注如何以一種靈活的方式設計和組織物件和類,以滿足系統複用和擴充套件的需求。
七大原則
1 迪米特法則
1.1 定義
如果兩個類不必彼此直接通訊,那麼這兩個類就不應當發生直接的相互作用。
如果其中一個類需要呼叫另一個類的某一個方法的話,可以透過第三者轉發這個呼叫。
1.2 說明
前提共識:在類的結構設計上,每一個類都應當儘量降低成員的訪問許可權。
根本思想:強調了類之間的松耦合。
生活中的思想體現的舉例:
你第一天去公司,怎麼會認識 IT部的人呢?
如果公司有很好的管理,那麼應該是人事的小楊打個電話到IT部,告訴主管安排人給小菜你裝電腦,
就算開始是小菜負責,他臨時有急事,主管也可以再安排小李來處理。
由於IT 部是抽象的,哪怕裡面的人都離職換了新人,我的電腦出問題也還是可以找IT部解決,而不需要認識其中的同事。
類之間的耦合越弱,越有利於複用,一個處在弱耦合的類被修改,不會對有關係的類造成波及。
資訊的隱藏促進了軟體的複用。
2 開放-封閉原則
2.1 定義
軟體實體(類、模組、函式等等)應該可以被擴充套件,但是不可被修改。
2.2 本原則的兩個特徵
1.對於擴充套件是開放的(Open for extension)
2.對於更改是封閉的(Closed for modification)
2.3 說明
做任何系統的時候,都不要指望系統一開始時需求確定,就再也不會變化。
怎樣的設計才能面對需求的改變卻可以保持相對穩定、安全,從而使得系統可以在第一個版本以後不斷推出新的版本呢?
開放-封閉給我們答案。(就是多擴充套件,少修改)
1.
你設計的時候,時刻要考慮,儘量讓這個類是足夠好。
寫好了就不要去修改了,如果新需求來,我們增加一些類就完事了,原來的程式碼能不動則不動。
2.
絕對的對修改關閉是不可能的。
無論模組是多麼的'封閉',都會存在一些無法對之封閉的變化。
既然不可能完全封閉,設計人員必須對於他設計的模組應該對哪種變化封閉做出選擇。
他必須先猜測出最有可能發生的變化種類,然後構造抽象來隔離那些變化。
3.
猜測程式可能會發生的變化是很難做到的。
但我們卻可以在發生小變化時,就及早去想辦法應對發生更大變化的可能。
也就是說,等到變化發生時立即採取行動。(即當你發現現有程式碼結構不靈活、不適用未來的持續開發、不適用未來潛在需要的可擴充套件的需要時)
在我們最初編寫程式碼時,假設變化不會發生。
當變化發生時,我們就建立抽象來隔離以後發生的同類變化。(即不同程度的重構!)
具體行動的做法:
在儘量減少已有程式碼的修改,然後重構。
然後面對新需求,對程式的改動是透過增加新程式碼進行的,而不是更改現有的程式碼。
不立即行動的後果:
“我們希望的是在開發工作展開不久就知道可能發生的變化。
查明可能發生的變化所等待的時間越長,要建立正確的抽象就越困難。”
如果不靈活的程式碼都在很多地方應用了,再考慮抽象、考慮分離,就很困難。
2.4 小結
開放-封閉原則是物件導向設計的核心所在。
開發人員應該僅對程式中呈現出頻繁變化的那些部分做出抽象。
對於應用程式中的每個部分都刻意地進行抽象同樣不是一個好主意。
拒絕不成熟的抽象和抽象本身一樣重要。切記,切記。
3 依賴倒轉原則
3.1 定義
A.高層模組不應該依賴低層模組。兩個都應該依賴抽象。
B.抽象不應該依賴細節。細節應該依賴抽象。
3.2 說明
說白了,就是要根據介面(即是計算機世界中的某種標準和協議)來程式設計,不要對根據具體實現來程式設計。
程序導向的開發時,為了使得常用程式碼可以複用,一般都會把這些常用程式碼寫成許許多多函式的程式庫。
這樣我們在做新專案時,去呼叫這些低層的函式就可以了。
這也就叫做高層模組依賴低層模組。
問題也就出在這裡。
我們要做新專案時,發現業務邏輯的高層模組都是一樣的,
但客戶卻希望使用不同的資料庫或儲存資訊方式,這時就出現麻煩了。
高層模組都是與低層的訪問資料庫繫結在一起的,沒辦法複用這些高層模組,這就非常糟糕了。
就像剛才說的,PC 裡如果 CPU、記憶體、硬碟都需要依賴具體的主機板,主機板一壞,所有的部件就都沒用了。
這顯然不合理。
4 里氏替換原則
4.1 定義
子類必須能夠替換掉它們的父類。
4.2 舉例
問:
如果在物件導向設計時,一個是鳥類,一個是企鵝類,如果鳥是可以飛的,企鵝不會飛。
那麼,企鵝是鳥嗎? 企鵝可以繼承鳥這個類嗎?
答:
類擁有父類所有非 private 的行為和屬性。
鳥會飛,而企鵝不會飛。
儘管在生物學分類上,企鵝是一種鳥,但在程式設計世界裡,企鵝不能以父類——鳥的身份出現。
因為前提說所有鳥都能飛,而企鵝飛不了。
所以,企鵝不能繼承鳥類。
4.3 說明
只有當子類可以替換掉父類,軟體單位的功能不受到影響時,父類才能真正被複用。
而子類也能夠在父類的基礎上增加新的行為。
說白了,本原則是,在貫徹開閉原則且涉及類的繼承時的一條注意事項。
擴充套件的時候(開閉原則),注意要保證擴充套件的子類,相容已有的程式碼、支援已有的功能。
4.4 小結
正是由於子型別的可替換性才使得使用父類型別的模組在無需修改的情況下就可以擴充套件。
再回過頭來看依賴倒轉原則,高層模組不應該依賴低層模組,兩個都應該依賴抽象,對這句話你會有更深入的理解。