一、引子
從學(xué)編程一開始就被告知,要想做一名優(yōu)秀的程序員兩大必要技能:1.源碼閱讀(JDK、C等底層語言封裝) 2.設(shè)計模式(使用某種語言優(yōu)雅的落地典型場景功能)。一般隨著工作年限的增長,被迫對底層語言/框架源碼閱讀的越來愈多,但是設(shè)計模式如不刻意去學(xué)習(xí),永遠不會真正掌握。筆者把設(shè)計模式比喻成程序員的“絕世神功”,掌握了設(shè)計模式,對快速閱讀源碼、優(yōu)雅地編寫程序有極大的促進作用,可以說就像打通了任督二脈一樣。
1.1 設(shè)計模式由來
1995年,GoF(Gang of Four四人幫)合作出版了《設(shè)計模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》(Design Patterns – Elements of Reusable Object-Oriented Software) 一書,書中總結(jié)了23種面向?qū)ο笤O(shè)計模式,也就是大名鼎鼎的GOF設(shè)計模式。
1.2 23種 VS 24種
一直聽說有24種設(shè)計模式(網(wǎng)上一大堆標題24種設(shè)計模式,然后列舉的只有23種,也是無語),公認的GOF只有23種,還有一種是啥?大部分文章都說是簡單工廠模式(Simple Factory)。筆者搜遍全網(wǎng)(連chatGPT也問了),沒找到第24種設(shè)計模式誰提出的。這第24種設(shè)計模式,有說是簡單工廠模式,也有說是靜態(tài)工廠模式,也有說簡單工廠模式=靜態(tài)工廠模式,真是一塌糊涂,亂七八糟。神奇的是這些文章的作者都沒深究過這個問題,估計大都是拿來主義。
到底幾種?
---23種?。?!即GOF的23種設(shè)計模式即可。還有2個模式:簡單工廠、靜態(tài)工廠,確實在后續(xù)應(yīng)用比較多,但在1995年未列入GOF。
二、知識預(yù)備
想要練成絕世武功,內(nèi)功心法和外家套路缺一不可。要想練成“設(shè)計模式”這一絕世武功,“面向?qū)ο笤O(shè)計原則”就是內(nèi)功心法(遵循的設(shè)計原則),“UML統(tǒng)一建模語言”就是外家套路(代碼落地建模工具)。練功之前,咱們先簡單學(xué)習(xí)下這2個必備的基礎(chǔ)技能。
2.1 面向?qū)ο笤O(shè)計原則
面向?qū)ο笤O(shè)計的目標之一就是支持可維護性復(fù)用,一方面需要實現(xiàn)設(shè)計方案的重用,另一方面要確保系統(tǒng)易于拓展和修改,具有較好的靈活性。7種面向?qū)ο笤O(shè)計原則,其中前5條是強約束性的建議都做到,后2條盡量做到即可。
1、單一職責原則(Single Responsibility Principle , SRP):一個對象應(yīng)該只包含單一的職責,并且該職責被完整地封裝在一個類中。--單一職責原則是實現(xiàn)高內(nèi)聚低耦合的指導(dǎo)方針。
理解:
- 一個類只負責一個職責。
2、開閉原則(Open Close Principle):對擴展開放,對修改關(guān)閉。--開閉原則是面向?qū)ο笤O(shè)計的目標。
理解:
- 使用接口和抽象類。實現(xiàn)不修改原代碼,又可以拓展新方法。
3、里氏代換原則(Liskov Substitution Principle):所有引用基類(父類)的地方必須能透明地使用其子類的對象。--里氏代換原則是實現(xiàn)開閉原則的基礎(chǔ)。
理解:
- 把父類設(shè)計為抽象類或者接口。
- 子類必須實現(xiàn)父類的所有方法。
4、依賴倒轉(zhuǎn)原則(Dependence Inversion Principle):高層模塊不應(yīng)該依賴低層模塊,它們都應(yīng)該依賴抽象。抽象不依賴于細節(jié),細節(jié)應(yīng)該依賴于抽象。--依賴倒轉(zhuǎn)原則就是面向?qū)ο笤O(shè)計的主要手段。
理解:
- 要針對接口編程,不要針對實現(xiàn)編程。
- 依賴注入:將一個類的對象傳入另一個類,注入時盡量注入父類對象,程序運行時通過子類對象覆蓋父類對象。
5、接口隔離原則(Interface Segregation Principle):客戶端不應(yīng)該依賴那些它不需要的接口(方法),--接口級的單一職責原則。
理解:
- 大接口要分割成小接口,接口專用。
- 客戶端使用專用接口。
6、迪米特法則(Demeter Principle):即最少知道原則,一個實體應(yīng)當盡量少的與其他實體之間發(fā)生相互作用,減少耦合。
理解:
- 依賴者只依賴該依賴的對象,被依賴者只暴露該暴露的對象。
7、合成復(fù)用原則(Composite Reuse Principle):盡量使用合成/聚合的方式,而不是使用繼承,降低耦合。
理解:
- 少用繼承,降低耦合。
2.2 UML建模
UML1.X有9個圖,UML2.0有12個圖,具體如下圖所示:
一般,我們掌握 UML1.X 常用的9種圖即可,分為兩類:
- 靜態(tài)圖:用例圖、類圖、包圖、對象圖、部署圖
- 動態(tài)圖:順序圖(時序圖),通信圖(UML1.x 時稱為協(xié)作圖),狀態(tài)機圖,活動圖
本文需要使用靜態(tài)圖的一種:類圖。關(guān)注類圖中類之間的6種關(guān)系(耦合度大小排序):泛化 = 實現(xiàn) > 組合 > 聚合 > 關(guān)聯(lián) > 依賴。
2.2.1 類圖-關(guān)聯(lián)關(guān)系
- 1.泛化:指的是繼承關(guān)系,表達一般和特殊。符號:空心三角箭頭的實線,箭頭指向父類。(注:UML中只有泛化,繼承是開發(fā)角度的描述。)
- 2.實現(xiàn):指的是類與接口的關(guān)系,表達類實現(xiàn)了接口的特征行為。符號:帶三角箭頭的虛線,箭頭指向接口。
- 3.組合:指的是整體與部分的關(guān)系, 但部分不能離開整體而單獨存在。符號:帶實心菱形的實線,菱形指向整體。
- 4.聚合:指的是整體和部分關(guān)系,且部分可以離開整體而單獨存在。符號:空心菱形的實心線,菱形指向整體。
- 5.關(guān)聯(lián):指的是類和類的關(guān)系,表達一個類知道另一個類的屬性和方法。符號:帶普通箭頭(或?qū)嵭娜切渭^)的實心線。
- 6.依賴:指的是使用的關(guān)系, 即一個類的實現(xiàn)需要另一個類的協(xié)助, 所以要盡量不使用雙向的互相依賴。符號:帶箭頭的虛線,指向被依賴的類。
2.2.2 類圖-表示方法
- 從上到下分為3部分:類名、屬性、方法。
- 符號含義:+ public、- private、#protected
三、設(shè)計模式
本節(jié)列舉24種設(shè)計模式,其中創(chuàng)建型模式6種、結(jié)構(gòu)型模式7種、行為型模式11種。每個模式從3個角度進行分析:定義、UML類圖、應(yīng)用。
3.1 創(chuàng)建型模式
創(chuàng)建型模式,就是用來創(chuàng)建對象的。包含3塊:單例/原型模式、工廠模式(簡單工廠、工廠方法、抽象工廠)、建造者模式。
1.單例模式(Singleton)
定義:保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。
UML類圖:
?
應(yīng)用:待補充
2.原型模式(Prototype)
定義:用原型實例指定創(chuàng)建對象的種類,并且通過拷貝這個原型來創(chuàng)建新的對象。
UML類圖:
?
3.簡單工廠模式(Static Factory Method Pattern)
定義:定義一個工廠類,使用static方法創(chuàng)建對象。根據(jù)不同參數(shù)返回不同實例,每增加一個對象需要修改工廠類,違背了“開閉原則”。--不推薦使用。
UML類圖:
應(yīng)用:
- Calendar 類獲取日歷類對象,static getInstance方法,根據(jù)參數(shù)獲取一個Calendar子類對象。
- Logback 中的 LoggerFactory日志工廠 ,static getLogger方法根據(jù)name/Class獲取 Logger 對象。
- Spring的BeanFactory接口,getBean(),根據(jù)name/Class獲取不同對象,但不是static修飾的,嚴格來說不算簡單工廠。
4.工廠方法模式(Factory Method)
定義:定義一個用于創(chuàng)建對象的接口,讓子類決定將哪一個類實例化。此模式使一個類的實例化延遲到其子類。
UML類圖:
應(yīng)用:
- java.net.URLStreamHandlerFactory作為工廠方法接口,定義了抽象方法createURLStreamHandler創(chuàng)建產(chǎn)品URLStreamHandler。工廠方法實現(xiàn)類為sun.misc.Launcher內(nèi)部類Factory。
5.抽象工廠模式(Abstract Factory)
定義:提供一個創(chuàng)建一系列相關(guān)或相互依賴對象的接口,而無需指定它們具體的類。用于創(chuàng)建一個產(chǎn)品族的產(chǎn)品。
UML類圖:
?
應(yīng)用:
- java.sql.Connection接口就是抽象工廠接口,定義了創(chuàng)建Statement產(chǎn)品族:Statement createStatement()、PreparedStatement prepareStatement(String sql)、CallableStatement prepareCall(String sql) 。PgConnection impl BaseConnection(extends Connection)就是一個具體工廠,專用于PostgreSql數(shù)據(jù)庫的連接工廠。PgConnection復(fù)寫了Statement產(chǎn)品族(3個創(chuàng)建)方法。
6.建造者模式(Builder)
定義:將一個復(fù)雜對象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
UML類圖:
?
?應(yīng)用:
- 實際應(yīng)用中,具體建造者Builder一般直接使用靜態(tài)內(nèi)部類實現(xiàn)。創(chuàng)建產(chǎn)品時類似:XXX.Builder(參數(shù)1,參數(shù)2,...).build()。Mybatis源碼org.apache.ibatis.builder包下:MapperBuilderAssistant指揮者中,產(chǎn)品有:ParameterMap、ParameterMapping、ResultMap、、ResultMapping、Discriminator、MappedStatement等。每個產(chǎn)品都有自己的建造者靜態(tài)內(nèi)部類Builder(定義了build())。
3.2 結(jié)構(gòu)型模式
1.適配器模式(Adapter)
定義:將一個類的接口轉(zhuǎn)換成客戶希望的另外一個接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
UML類圖:

應(yīng)用:
Spring AOP中,org.springframework.aop.framework.adapter包下的AdvisorAdapter接口,有3個適配器實現(xiàn)類:AfterReturningAdviceAdapter、MethodBeforeAdviceAdapter、ThrowsAdviceAdapter把每一個Advisor中的Advice都要適配成對應(yīng)的MethodInterceptor對象。這里使用的是方式二對象適配器的變種。比如MethodBeforeAdviceAdapter適配器通過getInterceptor()獲取到MethodBeforeAdviceInterceptor,最終結(jié)合攔截器模式(非GOF23),調(diào)用advice的advice.before()實現(xiàn)。
- 目標接口:AdvisorAdapter接口
- 適配者:MethodBeforeAdvice接口
- 適配器:MethodBeforeAdviceAdapter(advisor->advice)+MethodBeforeAdviceInterceptor(把適配者advice做入?yún)?gòu)造,最終調(diào)用適配者方法執(zhí)行)
比較復(fù)雜,圖示如下:
2.橋接模式(Bridge)
定義:將抽象部分與它的實現(xiàn)部分分離,使它們都可以獨立地變化。
UML類圖:

拆出一個維度出來,進行聚合,可有效減少子類的個數(shù)。原本維度1個數(shù)*維度2個數(shù)->維度1個數(shù)的子類+維度2個數(shù)的聚合實現(xiàn)+1個聚合接口
應(yīng)用:
java.sql包下的Driver和Connection接口,通過DriverManager進行橋接(不像圖中的聚合實現(xiàn))。DriverManager定義了registerDriver和getConnection方法。registerDriver可以注冊各種驅(qū)動。Connection接口可實現(xiàn)連接多種數(shù)據(jù)庫。2個維度分開進行拓展實現(xiàn),進行了脫耦。
3.組合模式(Composite)
定義:將對象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)。它使得客戶對單個對象和復(fù)合對象的使用具有一致性。
UML類圖:

組合模式分為透明式(樹枝特有方法在抽象類中體現(xiàn),樹葉類復(fù)寫空實現(xiàn),客戶端使用時無需區(qū)分樹枝還是樹葉)和安全式(樹枝特有方法在樹枝類中體現(xiàn))。當節(jié)點具有一致行為時采用透明式,當各節(jié)點行為不一致較多或樹枝節(jié)點較為健壯時采用安全式。
應(yīng)用:
- Map接口作為Component容器接口;HashMap作為Composite樹枝、Node實現(xiàn)了Map接口下的唯一接口Entry<K,V>kv映射實體接口作為Leaf樹葉,HashMap有一個屬性Node<K,V>[] table鏈表首歌節(jié)點組成的數(shù)組,可理解為聚合了Map接口。HashMap復(fù)寫putAll(Map<? extends K, ? extends V> m),可理解為樹枝的特有方法(Node沒有),很明顯這是安全式組合模式。
4.裝飾器模式(Decorator)
定義:動態(tài)地給一個對象添加一些額外的職責。就擴展功能而言, 它比生成子類方式更為靈活。
UML類圖:
應(yīng)用:待補充
5.外觀模式(Facade)
定義:為子系統(tǒng)中的一組接口提供一個一致的界面,F(xiàn)acade模式定義了一個高層接口,這個接口使得這一子系統(tǒng)更加容易使用。
UML類圖:
應(yīng)用:待補充
6.享元模式(Flyweight)
定義:運用共享技術(shù)有效地支持大量細粒度的對象。
UML類圖:
應(yīng)用:待補充
7.代理模式(Proxy)
定義:為其他對象提供一個代理以控制對這個對象的訪問。
UML類圖:
應(yīng)用:待補充
3.3 行為型模式
1.責任鏈模式(Chain of Responsibility)
定義:解除請求的發(fā)送者和接收者之間耦合,而使多個對象都有機會處理這個請求。將這些對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它。
UML類圖:
應(yīng)用:待補充
2.命令模式(Command)
定義:將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數(shù)化;對請求排隊或記錄請求日志,以及支持可取消的操作。
UML類圖:
應(yīng)用:待補充
3.解釋器模式(Interpreter)
定義:給定一個語言, 定義它的文法的一種表示,并定義一個解釋器, 該解釋器使用該表示來解釋語言中的句子。
UML類圖:
應(yīng)用:待補充
4.迭代器模式(Iterator)
定義:提供一種方法順序訪問一個聚合對象中各個元素,而又不需暴露該對象的內(nèi)部表示。
UML類圖:
應(yīng)用:待補充
5.中介者模式(Mediator)
定義:用一個中介對象來封裝一系列的對象交互。中介者使各對象不需要顯式地相互引用,從而使其耦合松散,而且可以獨立地改變它們之間的交互。
UML類圖:
應(yīng)用:待補充
6.備忘錄模式(Memento)
定義:在不破壞封裝性的前提下,捕獲一個對象的內(nèi)部狀態(tài),并在該對象之外保存這個狀態(tài)。這樣以后就可將該對象恢復(fù)到保存的狀態(tài)。
UML類圖:
應(yīng)用:待補充
7.觀察者模式(Observer)
定義:定義對象間的一種一對多的依賴關(guān)系,以便當一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知并自動刷新。
UML類圖:
應(yīng)用:觀察者模式
8.狀態(tài)模式(State)
定義:允許一個對象在其內(nèi)部狀態(tài)改變時改變它的行為。對象看起來似乎修改了它所屬的類。
UML類圖:
應(yīng)用:待補充
9.策略模式(Strategy)
定義:定義一系列的算法,把它們一個個封裝起來, 并且使它們可相互替換。本模式使得算法的變化可獨立于使用它的客戶。
UML類圖:
應(yīng)用:待補充
10.模板方法模式(Template Method)
定義:定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。Template Method使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。
UML類圖:
應(yīng)用:待補充
11.訪問者模式(Visitor)
定義:表示一個作用于某對象結(jié)構(gòu)中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。
UML類圖:
應(yīng)用:待補充
===參考===================
設(shè)計模式總結(jié)
設(shè)計模式與23種設(shè)計模式的簡單介紹文章來源:http://www.zghlxwxcb.cn/news/detail-516457.html
淺談UML中常用的9種圖文章來源地址http://www.zghlxwxcb.cn/news/detail-516457.html
到了這里,關(guān)于一文掌握設(shè)計模式(定義+UML類圖+應(yīng)用)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!