Head First设计模式整理
最近看了head first的設(shè)計(jì)模式頗有心得,趕緊趁熱整理下,便于以后觀看。
運(yùn)用設(shè)計(jì)模式的最基本的思想其實(shí)是眼光,因?yàn)樵O(shè)計(jì)模式的使用并不能幫助你簡化該功能的實(shí)現(xiàn),相反經(jīng)常會讓這個(gè)功能的實(shí)現(xiàn)變得更復(fù)雜。因?yàn)槭褂迷O(shè)計(jì)模式是為了讓代碼更加健壯和更有彈性。說白了就是讓以后更好的維護(hù)和擴(kuò)展。當(dāng)你寫代碼的時(shí)候開始想我這樣寫如果以后要改了好不好改,如果要增加一個(gè)功能好不好增加的時(shí)候你就開始進(jìn)入設(shè)計(jì)模式的大門了。
設(shè)計(jì)原則:
設(shè)計(jì)原則才是最重要的思想,所謂的設(shè)計(jì)模式只是對設(shè)計(jì)原則的運(yùn)用。
1、封裝變化:將代碼中可能需要變化的地方獨(dú)立出來,不要和那些不需要變化的代碼混在一起。
2、要依賴抽象,不要依賴具體類。(面向抽象編程
3、多用組合,少用繼承。
4、盡量不要跨層調(diào)用,應(yīng)當(dāng)使上層調(diào)用下層的,不要讓下層調(diào)用上層。
5、對擴(kuò)展開放,對修改關(guān)閉。
6、一個(gè)類應(yīng)該只有一個(gè)引起變化的原因。
具體的設(shè)計(jì)模式:
1、策略模式:封裝一個(gè)算法家族,讓他們之間可以互相替換。
給一個(gè)算法家族定義一個(gè)統(tǒng)一的接口,然后讓家族里的每個(gè)成員實(shí)現(xiàn)這個(gè)接口。客服端持有該家族的統(tǒng)一接口而不是具體的實(shí)現(xiàn),這樣可以在家族內(nèi)互相替換。
比如一個(gè)計(jì)算器,先定義一個(gè)計(jì)算接口,分別有加減乘除四個(gè)具體計(jì)算的實(shí)現(xiàn),我們在計(jì)算的時(shí)候根據(jù)運(yùn)算符號決定使用哪個(gè)具體的計(jì)算類。通常策略模式跟簡單工廠一起使用(記住要封裝變化,在這里獲取具體的計(jì)算類是一個(gè)變化點(diǎn),其他的是不變的)。
2、工廠方法和抽象工廠
簡單工廠只是將生產(chǎn)對象這一變化點(diǎn)進(jìn)行封裝。
工廠方法:定義了一個(gè)創(chuàng)建對象的接口,但由子類決定要實(shí)例化的類是哪一個(gè)。
其代碼結(jié)構(gòu)圖跟策略模式一樣,但是兩者的作用不一樣。策略是為了封裝算法,工廠方法是為了實(shí)例化不同的對象。而且工廠方法并不一定需要定義一個(gè)單獨(dú)的新接口,就像模版方法一樣可以將接口定義在父類中,由子類去完成具體的實(shí)現(xiàn)。
抽象工廠:提供一個(gè)接口,用于創(chuàng)建相關(guān)或依賴對象的家族。
抽象工廠是為了創(chuàng)建一個(gè)對象家族而建立的,也就是說同一個(gè)抽象工廠的實(shí)現(xiàn)類中所生產(chǎn)的對象之間是有某種關(guān)聯(lián)關(guān)系的。
比較典型的例子就是配電腦:我們知道主板的cpu插槽和cpu的針腳存在一個(gè)匹配的關(guān)聯(lián)關(guān)系,這時(shí)候我們使用一個(gè)抽象工廠方法來保證獲取到的主板和cpu是匹配的。
3、觀察者模式:定義了對象之間的一對多依賴,這樣一來,當(dāng)一個(gè)對象改變狀態(tài)時(shí),它的所有依賴者都會收到通知并且自動更新。
這個(gè)模式比較好理解,具體實(shí)現(xiàn)就是定義一個(gè)觀察者接口和被觀察者接口,觀察者像被觀察者注冊時(shí),被觀察者持有觀察者對象,當(dāng)被觀察者發(fā)生變動時(shí),挨個(gè)通知觀察者。
4、裝飾者模式:動態(tài)的將責(zé)任附加到對象上。
要說到裝飾者模式就不能不提java的io,用的io的都知道,一個(gè)套一個(gè),有時(shí)候會套上很多層,這就是裝飾者模式。裝飾者模式的實(shí)現(xiàn)其實(shí)很簡單。首先定義一個(gè)統(tǒng)一的接口,然后實(shí)現(xiàn)一個(gè)最基本的底層實(shí)現(xiàn),接著就是裝飾者,裝飾者同樣實(shí)現(xiàn)統(tǒng)一的接口,同時(shí)持有一個(gè)該接口的引用(面向接口編程),裝飾者在之前或者之后調(diào)用所持有的對象的接口,這樣就可以使用裝飾者替換掉具體的實(shí)現(xiàn)類,完成額外的功能擴(kuò)展。
5、單例模式:確保一個(gè)類這有一個(gè)實(shí)例,并提供一個(gè)全局訪問點(diǎn)。
單例模式也比較好理解,使用的時(shí)候主要要注意線程同步的問題。它的比較通用的實(shí)現(xiàn)是雙重null判斷,并將第二層的null判斷加上同步鎖。還有一種是靜態(tài)內(nèi)部類獲取單例的實(shí)例。據(jù)說還有一種,是使用枚舉實(shí)現(xiàn),這個(gè)沒有嘗試過,有空試試。
6、命令模式:將請求封裝成命令接口,命令接口中持有實(shí)際執(zhí)行該動作或一系列動作的對象接口(這些接口并不統(tǒng)一),實(shí)現(xiàn)命令接口時(shí)實(shí)際上是調(diào)用各個(gè)實(shí)際執(zhí)行對象的實(shí)現(xiàn)。
命令模式其實(shí)就是在調(diào)用者和被調(diào)用者之間再插入一層,實(shí)現(xiàn)調(diào)用者和被調(diào)用者之間的解耦。這所以這樣做是因?yàn)楸徽{(diào)用者并不是統(tǒng)一的接口(書中的例子就是有電燈,空調(diào),冰箱等以后其他的電視什么亂七八糟的),如果不加入命令模式的話那么每次更換被調(diào)用者都要改變調(diào)用者的代碼,代價(jià)太大,加入命令模式之后,更改被調(diào)用者只需要調(diào)用調(diào)用者的setCommand方法重新設(shè)置新的命令即可。
7、適配器模式:將一個(gè)類的接口,轉(zhuǎn)換成客戶期望的另一個(gè)接口。
現(xiàn)在有A和B兩個(gè)接口,我們有B接口的實(shí)現(xiàn),但是客戶調(diào)用的是A接口的方法,這時(shí)候我們不能去修改客戶的接口,同時(shí)又不想再重新寫一遍A接口的實(shí)現(xiàn),我們可以用一個(gè)適配器來解決這個(gè)問題。所謂適配器C就是讓C實(shí)現(xiàn)接口A同時(shí)持有一個(gè)B接口的引用,當(dāng)調(diào)用C的A接口的方法是實(shí)際上是在調(diào)用B接口的具體實(shí)現(xiàn)。
8、外觀模式:定義一個(gè)統(tǒng)一的接口,用來訪問子系統(tǒng)中的一群接口。
顧名思義就是將一群有關(guān)聯(lián)的接口封裝成一個(gè)對外的接口,方便外部調(diào)用。通常用于一個(gè)外部功能需要多步子系統(tǒng)功能才能實(shí)現(xiàn)的場景。
9、模版方法模式:在一個(gè)方法中定義一個(gè)算法的骨架,而將一些步驟延遲到子類中。模版方法使得子類可以在不改變算法結(jié)構(gòu)的情況下,重新定義算法中的某些步驟。
這是我目前用的比較多的一個(gè)模式。這個(gè)模式的精髓就在于封裝相同的流程,并對某些通用子流程提供默認(rèn)實(shí)現(xiàn),將特定的子流程留給各子類實(shí)現(xiàn)。像我們通常對接其他系統(tǒng)的接口的時(shí)候,流程無非就是組裝參數(shù),獲取url,發(fā)送請求,解析響應(yīng),可以把這幾個(gè)子流程封裝在一個(gè)父類的方法里邊,讓各個(gè)子類去實(shí)現(xiàn)具體的子流程。
10、迭代器模式:提供一種方法順序訪問一個(gè)聚合對象中的各個(gè)元素,而又不暴露其內(nèi)部的表示。
這個(gè)模式可以看java的集合類,所有的集合類都實(shí)現(xiàn)了Iteratorable接口,這樣我們可以對所有的集合類進(jìn)行統(tǒng)一的讀取操作而不用管它具體是哪一種集合類以及它內(nèi)部的數(shù)據(jù)結(jié)構(gòu)是什么。
11、組合模式:允許你將對象組合成樹形結(jié)構(gòu)來表現(xiàn)“整體/部分”層次結(jié)構(gòu)。組合能讓客戶以一致的方式處理個(gè)別對象以及對象組合。
顧名思義,組合模式是將對象組合成樹形結(jié)構(gòu)的,具體的實(shí)現(xiàn)方式就是接口中持有一個(gè)本身的集合作為該節(jié)點(diǎn)的子節(jié)點(diǎn)。這里有兩種表示方式,一種是樹枝節(jié)點(diǎn)和葉子節(jié)點(diǎn)實(shí)現(xiàn)同一個(gè)接口,也就是葉子節(jié)點(diǎn)也擁有添加子節(jié)點(diǎn)和獲取子節(jié)點(diǎn)的方法,只不過在葉子節(jié)點(diǎn)中這兩種方法是直接拋出異常而沒有具體的實(shí)現(xiàn),這種方式可以讓客戶端對樹枝節(jié)點(diǎn)和葉子節(jié)點(diǎn)一樣的處理。另外一種就是葉子節(jié)點(diǎn)和樹枝節(jié)點(diǎn)實(shí)現(xiàn)不同的接口,從接口上就講兩者區(qū)分,這樣避免了對葉子節(jié)點(diǎn)進(jìn)行獲取子節(jié)點(diǎn)等操作,但是這樣的話客戶端就需要認(rèn)識兩種接口。具體使用哪一種方式看自己需要而定。同時(shí)組合模式的內(nèi)部也是一種數(shù)據(jù)結(jié)構(gòu),所以一般組合模式會跟迭代器模式一起使用。
12、狀態(tài)模式:允許對象在內(nèi)部狀態(tài)改變時(shí)改變它的行為。
狀態(tài)模式的結(jié)構(gòu)圖跟策略模式的結(jié)構(gòu)圖基本一樣,但是兩者的目的不相同。策略模式是單個(gè)行為之間的相互替換,而狀態(tài)模式是每一個(gè)狀態(tài)都得實(shí)現(xiàn)主類的所有行為。例如鴨子有三種狀態(tài):吃飽、正常、饑餓;有三種行為:飛行、叫、跑;每種行為在每個(gè)狀態(tài)下的表現(xiàn)都不一樣,那就意味著每一個(gè)狀態(tài)都要分別實(shí)現(xiàn)鴨子的三個(gè)行為,這就是狀態(tài)模式。具體的實(shí)現(xiàn)方式是主類持有一個(gè)當(dāng)前狀態(tài),主類的具體行為實(shí)際調(diào)用的是當(dāng)前狀態(tài)的行為,每當(dāng)某種條件達(dá)到時(shí)主類的當(dāng)前狀態(tài)會切換成其他狀態(tài)以達(dá)到更改主類行為的目的。
13、代理模式:為另一個(gè)對象提供一個(gè)替身或占位符以控制對這個(gè)對象的訪問。
這個(gè)模式跟裝飾者模式非常相似,但是同樣的,兩者的目的不同。裝飾者模式的目的是為了改變被裝飾類的行為,而代理模式的主要目的是控制對像的訪問。可能有人會說結(jié)構(gòu)一樣就是一樣的模式啊。其實(shí)不然,你所要解決的問題決定你使用哪個(gè)模式,哪怕他們的結(jié)構(gòu)一摸一樣,這一點(diǎn)是必須要明確的。
記住設(shè)計(jì)模式是用來解決問題的,而不是為了使用而使用。設(shè)計(jì)模式解決的并不是如何實(shí)現(xiàn)這個(gè)功能的問題,也就是說使用了設(shè)計(jì)模式你實(shí)現(xiàn)這個(gè)功能很有可能會更復(fù)雜,要寫更多的代碼,但是你以后維護(hù)或者擴(kuò)展的時(shí)候卻非常的方便。
總結(jié)
以上是生活随笔為你收集整理的Head First设计模式整理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前端学习(2122):项目演示
- 下一篇: HeadFirst设计模式-命令模式