I walk very slowly, but I never walk backwards
大家好~,我是寂然,本教程我們來學(xué)習(xí)設(shè)計模式,其實設(shè)計模式,好多人稱之為 " Java設(shè)計模式 ",但其實設(shè)計模式并不是 Java 的專利,它不依賴語言,同樣適用于 C++、C#、JavaScript 等其它面向?qū)ο蟮木幊陶Z言,這是首先要和大家明確的一點,Java 是典型的面向?qū)ο蟮木幊陶Z言,所以本教程以 Java 為基礎(chǔ)來講解設(shè)計模式
內(nèi)容介紹
凡事預(yù)則立,不預(yù)則廢,再開始學(xué)習(xí)一門新的課程之間,我們首先要來明確一下學(xué)習(xí)的內(nèi)容及路線,首先,在正式的內(nèi)容開始之前,我們首先要明確以下兩點
為什么要學(xué)習(xí)設(shè)計模式,以及設(shè)計模式的重要性
-
設(shè)計模式的產(chǎn)生背景以及概念
然后會依次給大家介紹設(shè)計模式七大設(shè)計原則,認(rèn)識UML類圖以及類圖六大關(guān)系,設(shè)計模式的分類以及二十三種設(shè)計模式全面解析,當(dāng)然,不是蜻蜓點水哈,本教程中的每一個設(shè)計模式,我會給大家采用如下路線進(jìn)行全面介紹
舉例應(yīng)用場景 -> 設(shè)計模式介紹 -> 分析實現(xiàn)步驟 -> 代碼案例實操 -> 框架或項目中用到該模式的源碼分析
最后,希望大家通過本系列的學(xué)習(xí),掌握多種設(shè)計模式的實現(xiàn)和本質(zhì),能夠在工作中靈活運用解決實際問題,寫出優(yōu)雅并且維護性可讀性高的代碼,那我們開始啟程吧
為什么要學(xué)設(shè)計模式
其實類似大家這樣有一定工作經(jīng)驗的開發(fā)人員,了解以及進(jìn)一步掌握設(shè)計模式是非常有必要的,因為平時大家接到開發(fā)任務(wù),首要目標(biāo)是實現(xiàn)功能,而且現(xiàn)在的節(jié)奏~,時間緊,任務(wù)重,大家沒有,可能也來不及做其他的考慮,所以,大部分程序員寫的代碼,其實可維護性,可讀性都很差,類之間的關(guān)系非常復(fù)雜,沒有條理,那例如以后要增加新的需求,現(xiàn)有的程序如何進(jìn)行變動成本最低?如何保證新的功能模塊不會對原來的項目產(chǎn)生影響?
案例引入
舉個栗子,大家看下如下兩張圖
?

茅草小屋大家應(yīng)該都看到過,一個簡單的架構(gòu),蓋幾捆茅草,他不需要什么設(shè)計,也不需要花時間合理去架構(gòu),設(shè)計他的初衷是為了遮風(fēng)擋雨,大家可類比于單一的應(yīng)用架構(gòu),個人開發(fā),一個應(yīng)用就能將所有的功能部署在一起,打個war包扔到tomcat里即可運行,由于模型簡單,代碼層面也不需要考慮太多,重點在于功能的實現(xiàn)
?

那大家來看圖二的摩天大廈,一座這樣的建筑,可以直接開工嘛?顯示是不可以的,在項目開始之前,設(shè)計師需要畫設(shè)計圖紙,考慮大廈的采光,通風(fēng),安全通道,承重...,做大量的準(zhǔn)備工作
同樣,大家可以類比于現(xiàn)在的分布式微服務(wù)項目,隨著項目的復(fù)雜度直線上升,在項目開始之前,要進(jìn)行需求宣講,架構(gòu)設(shè)計評審...,這樣的項目都是團隊合作,除了要考慮服務(wù)之間的交互,服務(wù)內(nèi)部代碼的可讀性,可靠性,可維護性都是我們需要重點考慮的,這時候,設(shè)計模式就顯得尤為重要
設(shè)計模式可以讓你知道在某些場景下如何來設(shè)計出適合場景的架構(gòu),通俗點說,可以讓你的代碼更加“優(yōu)雅”
設(shè)計模式的重要性
當(dāng)然,設(shè)計模式,大家可以通俗理解為是前輩程序員在大量開發(fā)中累積的經(jīng)驗,掉了大量的頭發(fā),然后歸納為了這些設(shè)計模式,當(dāng)然,設(shè)計模式絕不是代表了絕對的開發(fā)真理,在問題面前應(yīng)該靈活變通,當(dāng)你的代碼類結(jié)構(gòu)合理, 易于維護 ,可擴展性強,那么設(shè)計模式的目的就已經(jīng)達(dá)到了,切記不要過渡的使用設(shè)計模式,為了用而用
當(dāng)然,上面的說法還是針對于大牛而言的,對于咱們這種幾年經(jīng)驗的碼農(nóng),掌握設(shè)計模式就很有必要,當(dāng)大家學(xué)習(xí)并且使用到設(shè)計模式,如果你的項目做的非常大,之間關(guān)系非常復(fù)雜的時候,仍然能讓你能掌控這些代碼,不會出現(xiàn)代碼失控的情況,如同上面的案例,設(shè)計模式就是設(shè)計大廈的圖紙
其次,很多成熟框架的源碼里大量的用到了設(shè)計模式,如果掌握設(shè)計模式,對于閱讀源碼會有很大的幫助,
如果你要學(xué)習(xí)源碼,那么學(xué)習(xí)完設(shè)計模式再看的話,會更加清晰
設(shè)計模式的背景
設(shè)計模式最早出現(xiàn)在建筑領(lǐng)域,是克里斯托弗.亞歷山大(Christopher Alexander,頭銜很多的大佬) 對環(huán)境中不斷出現(xiàn)的問題, 總結(jié)出這些問題的解決方案。以后再遇到這些問題時,可以重用這些方案來解決
四人幫(GOF)
1994年,有四位作者:Erich Gamma,Richard Helm,Ralph Johnson和John Vlissides發(fā)表了一本題為《設(shè)計模式 - 可重用的面向?qū)ο筌浖亍返膱D書,該書在軟件開發(fā)中開創(chuàng)了設(shè)計模式的概念,第一次將設(shè)計模式提升到理論高度,并將之規(guī)范化,這些作者被統(tǒng)稱為四人幫(GOF),如下就是這四個大佬~
?

設(shè)計模式的概念
其實,關(guān)于設(shè)計模式的概念,上面已經(jīng)作出解釋,當(dāng)然,我們來看下設(shè)計模式的官方概念
設(shè)計模式(design pattern)是對軟件設(shè)計中普遍存在(反復(fù)出現(xiàn))的各種問題,所提出的解決方案
這個術(shù)語是由埃里希·伽瑪(Erich Gamma)等人在 1990 年代從建筑設(shè)計領(lǐng)域引入到計算機科學(xué)的
設(shè)計模式的原則
上面提到了,我們?yōu)槭裁匆獙W(xué)習(xí)設(shè)計模式,在這里做一個簡單的總結(jié)
設(shè)計模式是為了讓軟件(程序)具有更好的代碼重用性,可讀性,可擴展性,可靠性
理論聽著云里霧里,那到底是什么意思呢?舉個栗子,何為具有更好的可靠性呢?
- 代碼重用性:即相同功能的代碼,不需要多次編寫,可以重復(fù)使用
- 可讀性:即編碼的規(guī)范性,便于其他程序員閱讀和理解
- 可擴展性:即當(dāng)需要增加新功能時,成本低,也稱為可維護性
- 可靠性:即代碼強壯,當(dāng)增加新的功能時,對原有的功能沒有影響
其實說到底,就是讓程序呈現(xiàn)出高內(nèi)聚,低耦合的特性
高內(nèi)聚&低耦合
耦合主要描述模塊之間的關(guān)系,內(nèi)聚主要描述模塊內(nèi)部,當(dāng)然模塊的粒度可大可小(小到一個類 大-到一個系統(tǒng))
高內(nèi)聚 一個功能模塊內(nèi)部的元素,關(guān)聯(lián)越強,則內(nèi)聚越高,模塊的單一性更強,一個模塊應(yīng)當(dāng)盡可能獨立完成某個功能
低耦合 功能模塊和功能模塊之間耦合性很低,A模塊出現(xiàn)問題,避免影響B(tài)模塊,比如模塊A直接操作了模塊B中數(shù)據(jù), 則視為強耦合,例如下圖,我們假設(shè)這樣一個場景,發(fā)貨系統(tǒng)發(fā)貨,寫入消息隊列,訂單系統(tǒng)這邊訂閱消息隊列里的消息,如果訂單系統(tǒng)出現(xiàn)故障,不影響發(fā)貨系統(tǒng)正常寫入消息隊列,利用了消息中間件,兩個系統(tǒng)之間的耦合性大大降低
?

設(shè)計模式原則引出
理解了高內(nèi)聚&低耦合之后,我們正式進(jìn)入到設(shè)計模式七大原則,那么,何為設(shè)計模式的原則呢?
其實是程序員在編程時,應(yīng)當(dāng)遵守的原則,也是各種設(shè)計模式的基礎(chǔ) (即:設(shè)計模式為什么 這樣設(shè)計的依據(jù))
所以,我們先來認(rèn)識一下設(shè)計模式常用的七大原則:
單一職責(zé)原則、接口隔離原則、依賴倒置原則、里氏替換原則、開閉原則、迪米特法則、合成復(fù)用原則
這些原則并不是孤立存在的,它們相互依賴,相互補充,下面表格對于七大原則進(jìn)行了一個簡單的介紹
| 名稱 | 設(shè)計原則簡介 | 重要性 |
|---|---|---|
| 單一職責(zé)原則 | 類的職責(zé)要單一,不能將太多的職責(zé)放在一個類中 | ★★★★☆ |
| 開閉原則 | 軟件實體對擴展是開放的,但對修改是關(guān)閉的,即在不修改一個軟件實體的基礎(chǔ)上去擴展其功能 | ★★★★★ |
| 里氏代換原則 | 在軟件系統(tǒng)中,一個可以接受基類對象的地方必然可以接受一個子類對象 | ★★★★☆ |
| 依賴倒置原則 | 要針對抽象層編程,而不要針對具體類編程 | ★★★★★ |
| 接口隔離原則 | 使用多個專門的接口來取代一個統(tǒng)一的接口 | ★★☆☆☆ |
| 合成復(fù)用原則 | 在系統(tǒng)中應(yīng)該盡量多使用組合和聚合關(guān)聯(lián)關(guān)系,盡量少使用甚至不使用繼承關(guān)系 | ★★★★☆ |
| 迪米特法則 | 一個軟件實體對其他實體的引用越少越好,或者說如果兩個類不必彼此直接通信,那么這兩個類就不應(yīng)當(dāng)發(fā)生直接的相互作用,而是通過引入一個第三者發(fā)生間接交互 | ★★★☆☆ |
設(shè)計原則和設(shè)計模式也是對系統(tǒng)進(jìn)行合理重構(gòu)的指南針,那么,何為合理重構(gòu)?
合理重構(gòu),是在不改變軟件現(xiàn)有功能的基礎(chǔ)上,通過調(diào)整程序代碼改善軟件的質(zhì)量、性能,使其程序的設(shè)計模式和架構(gòu)更趨合理,提高軟件的擴展性和維護性
下期預(yù)告
下一節(jié),我們正式進(jìn)入設(shè)計模式的學(xué)習(xí),我會為大家用多個案例分析,來解讀設(shè)計模式原則之單一職責(zé)原則,以及它的注意事項和細(xì)節(jié),從設(shè)計模式的原則開始,一步步走進(jìn)設(shè)計模式的大門,最后,希望大家在學(xué)習(xí)的過程中能夠感覺到設(shè)計模式的有趣之處,高效而愉快的學(xué)習(xí),下期見~
?