天天看點

《Head First Design Pattern 》--設計模式 讀書筆記

                   馬上校招就要開始了,我看了下我在履歷上寫下了如下:

熟練掌握面向對象程式設計,熟練掌握C/C++,了解STL,熟悉Python等腳本語言。

基礎紮實,熟悉常見的資料結構和算法、作業系統、計算機網絡、設計模式。

熟悉Linux系統基本操作、SQL Server等資料庫操作,了解TCP/IP通信協定。

英語聽說讀寫熟練,CET-6 

                   對照着看下,好像就設計模式這部分心裡沒底,以前也大緻掃了下《大話設計模式》,說實話,看了前兩章感覺還不錯,可是越看越看不下去,不知所雲,但是看了一些筆試面試面經發現好多面試官問應聘問懂不懂一些基礎的設計模式,是以對常用的設計模式還是要掌握了解下的,是以我打算還是好好看下《[Head First Design Pattern》和《大話設計模式》這兩本書,以争取對常用的設計模式有所了解來應付下面試中會涉及到一些基礎的有關設計模式方面的問題:

以往是代碼複用,現在是經驗複用。

當設計“維護”時候,為了複用(reuse)目的而使用的繼承,解決并不完美,回導緻很多問題,有此問題後,導緻了接口的産生,利用接口可以把要改變的剔除出來獨立成一個類接口,但是這樣會導緻重複代碼變多不能複用(接口的缺點),這樣做實質上是一個惡夢跳進另外一個惡夢,是以此時需要用到設計模式帶你走出此苦難......(ps:設計模式可以這樣完美的解決:類似于接口,但是接口下面定義各個行為的實作類,這樣就不用在子類中實作接口了。哈哈......)

哈哈,設計模式此時閃亮登場了.........

面向對象程式設計中貫穿的一些設計原則:

設計原則一:找出應用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的代碼混在一起。(這幾乎是每個設計模式背後的精神所在,所有的模式都提供了一套方法讓“系統中的某些部分改變而不會影響到其他部分”)

設計原則二:針對接口程式設計,而不是針對實作程式設計。

設計原則三:多用組合,少用繼承。(組合建立系統具有很大的彈性)

1.政策模式:定義了算法族,分别封裝起來,讓它們之間可以互相替換,此模式可以讓算法變化可以獨立于使用算法的客戶。

設計模式比庫的等級更高,設計模式告訴我們如何組織類和對象以解決某種問題。

我認為設計模式其實就是利用OO設計原則(當然這隻是通俗易懂的了解,實際要比這個複雜,呵呵)

在書上看到這樣的一句話,感覺很好----設計是一門藝術,總有血多可取舍的地方,但是如果你能采用這些經過深思熟慮,且經受過實際考驗的設計模式,你就領先别人了。

良好的OO設計必須具備可複用,可擴充,可維護三個特性。模式不是代碼,而是針對問題的通用解決方案,你可以把它們應用到特定的應用中去。

2.觀察着模式(observer)

讓你的對象知悉現況,觀察着模式是JDK中使用最多的模式之一,非常有用。

通俗了解:出版着(主題subject),訂閱着(觀察着observer)=觀察着模式

在真實的世界中,你通常會看到觀察者模式被定義成:觀察者模式定義了對象之間的一對多依賴,這樣依賴,當一個對象改變狀态時,它的所有依賴者都會收到通知并自動更新。

《Head First Design Pattern 》--設計模式 讀書筆記

松耦合的威力:

當兩個對象之間松耦合,它們依然可以互動,但是不太清楚彼此的細節,觀察者模式提供了一種對象涉及,讓主題和觀察者之間松耦合。

設計原則4:為了互動對象之間的松耦合設計而努力。(松耦合的設計能讓我們建立更有彈性的OO系統)

java中有内置的觀察者模式,java.util包内包含最基本的Observer接口(相當于observer接口)和observable類(相當于subject接口)

在JDK中,有很多地方都用到了觀察者模式,比如:在swing API:JBtuton的超類AbstractButton,會看到許多增加和删除傾聽者(listener)的方法,這些方法可以讓觀察者感應到Swing元件的不同類型的事件。

3.裝飾者模式

盡管繼承很強大,但是它并不總是能夠實作最有彈性和最好維護的設計。

可以利用組合(composition)和委托(delegation)可以在運作時具有繼承行為的效果。

代碼應該如同晚霞中的蓮花一樣地關閉(免于改變),如同晨曦中的蓮花一樣地開發(能夠擴充)

設計原則5:類應該對擴充開發,對修改關閉。(其實這聽起來是沖突的,但是有些聰明的技巧還是可以實作的,比如借助設計模式)

我們的目标是允許類容易擴充,在不修改現有代碼的情況下,就可以搭配新的行為。

裝飾者模式:動态地将責任附加到對象上,若要擴充功能,裝飾者提供了比幾次更有彈性的替代方案。

裝飾者該做的事就是增加行為到被包裝對象上。裝飾者模式一味這一群裝飾者類,這些類用來包裝具體元件。

裝飾者模式的缺點:雖然能為系統設計注入彈性,但是會在設計中加入大量的小類,這偶爾會導緻别人不太容易了解我的設計方式。拿JAVA I/O庫來說,人們第一次接觸這個庫時候旺旺無法輕易地了解它,但是如果他們能認識到這些類都是用來包裝InputStream的,一切都會變得簡單很多。

I/O的相關類都是裝飾者,

4.工廠模式

簡單工廠,雖然不是真正的設計模式,但仍不不失為一個簡單方法,可以将客戶程式成具體類解耦。

針對接口程式設計,可以隔離掉以後系統可能發生的一大堆改變。為什麼呢?如果代碼是針對接口而寫的,那麼通過多态,它可以 與任何新類實作該接口。但是,當代碼中使用大量的具體類時,等于是自找麻煩,應為一旦加入一個新的具體類,就必須改變代碼。也就是說,你的代碼并非“對修改關閉”。想用心的具體類類擴充代碼,就必須重新打開它,是以,該怎麼辦?遇到這樣的問題時候,就應該回到OO設計原則去尋找線索。

我們把類中建立對象的代碼從類中抽離,放到一個新的對象中,我稱這個新對象為“工廠”。工廠(factory)處理建立對象的細節。

所有工廠模式都用來封裝對象的建立,工廠方法模式(Factory Method Pattern)通過讓子類決定該建立的對象是什麼,來達到将對象建立的過程封裝的目的。(哈哈,這裡加入下本人的了解,工廠模式和簡單工廠模式的差別在于:原本有一個對象負責所有具體類的執行個體化,現在通過一些小的轉變,變成由一群子類來負責執行個體化。更通俗的了解就是工廠方法用來處理對象的建立,并将這一的行為封裝在子類中,這樣,客戶程式中關于超類的代碼和子類對象建立代碼解耦了。呵呵,更通俗地了解:簡單工廠吧全部的事情,在一個地方都處理完了,然而工廠方法卻是建立一個架構,讓子類決定要如何實作)

工廠方法模式:定義了一個建立對象的接口,但由子類決定執行個體化的類是哪一個。工廠方法讓類把執行個體化推遲到子類。

設計原則6:要依賴抽象,不要依賴具體類(又叫依賴倒置原則)

這個原則聽起來很像“針對接口程式設計,不針對實作程式設計”,不是嗎?的确很相似,然而這裡更強調“抽象”。這個原則說明了:不能讓高層元件依賴低層元件,而且,不管高層活低層元件,兩者都應該依賴于抽象。

下面的幾個知道方針,可以幫助你避免在OO設計中違法依賴倒置原則:

1.變量不可以持有具體類的引用(如果用new,就會持有具體類的引用,你可以改用工廠來避免這樣的做法)

2.不要讓類派生自具體類(如果派生來自具體類,你就會依賴具體類,請派生自一個抽象(接口或者抽象類))

3.不要覆寫幾類中已實作的方法(如果覆寫基類已實作的方法,那麼你的基類就不是一個真正适合被繼承的抽象,基類中已實作的方法,應該由所有的子類共享)

5.抽象工廠模式

抽象工廠模式:提供一個接口,用于建立相關活依賴對象的家族,而不需要明确指定具體類。

關于工廠模式和抽象工廠模式差別及聯系:

這兩個模式在把程式成特定現實中解耦方面真的都很有一套,隻是做法不同而已。(他們兩個都能将對象的建立封裝起來,使應用程式解耦,并降低對其特定實作的依賴)

工廠方法模式:
一個抽象産品類,可以派生出多個具體産品類。   
一個抽象工廠類,可以派生出多個具體工廠類。   
每個具體工廠類隻能建立一個具體産品類的執行個體。

抽象工廠模式:
多個抽象産品類,每個抽象産品類可以派生出多個具體産品類。   
一個抽象工廠類,可以派生出多個具體工廠類。   
每個具體工廠類可以建立多個具體産品類的執行個體。   
    
差別:
工廠方法模式隻有一個抽象産品類,而抽象工廠模式有多個。   
工廠方法模式的具體工廠類隻能建立一個具體産品類的執行個體,而抽象工廠模式可以建立多個。      

6.單件模式

其實實作一個類隻有一個執行個體化,可以定義一個全局變量就可以,但是單件模式實作不僅給我們一個全局的通路點,和全局變量一樣友善,又沒有全局變量的缺點(啥缺點?比方說,如果将對象指派給一個全局變量,那麼你必須在程式一開始就建立好對象對嗎?網易這個對象非常耗費資源,而程式在這次的執行過程中又一直沒用到它,這不就形成浪費了嗎?但是利用單件模式,我們可以在需要時候才建立對象,呵呵)

單件模式的源碼剖析--我們可以發現這個類沒有公開的構造器,隻能在類中構造。哈哈,此類中有個getInstance()靜态方法,外人要取得它的執行個體化,他們必須要請求得到一個執行個體,而不是自行執行個體化得到一個執行個體,調用這個靜态方法,它就立刻現身,随時可以工作。

單件模式:確定一個類隻有一個執行個體,并提供一個全局通路點。

單件模式在多線程下會出問題,可以通過增加synchonized關鍵字到getInstance()方法中,我們迫使每個線程在進入這個方法之前,要等候别的線程離開該方法,也就是說,不會有兩個線程可以同時進入這個方法,但是似乎同步的getInstance()的做法将拖垮性能,可以使用急切執行個體化和雙重檢查加鎖方法來改善。

7.指令模式

這個模式沒怎麼看懂,大緻是由餐廳點餐例子,點餐者,服務員,和廚師,通過指令模式,可以使服務員和廚師不需要交流(解耦),隻需通過訂單交流就行了。

個人了解:這個模式允許我們動作封裝成指令對象,這樣一來就可以随心所欲地儲存、傳遞和調用它們。(當需要将送出請求的對象和執行請求的對象解耦的時候,使用指令模式)

更通俗地了解:指令模式将送出請求的對象和執行請求的對象解耦,在被解耦的兩者之間是通過指令對象進行溝通的,指令對象封裝了接受者和一個或一組動作。

指令模式:将“請求”封裝成對象,以便使用不同的請求、隊列或者日志來參數化其他對象。指令模式也支援可撤銷的操作。

8.擴充卡模式

擴充卡模式:将一個類的接口,轉換成客戶期望的另一個接口。擴充卡讓原本接口不相容的類可以合作無間。

盡管定義了這個模式,但是其實實際上有“兩種”擴充卡:”對象“擴充卡和”類“擴充卡。對象擴充卡和類擴充卡使用了兩種不同的适配方法,分别是組合(對象擴充卡)和繼承(類擴充卡)。

9.外觀模式

我們還有一個改變接口的新模式,但是它改變接口的原因是為了簡化接口,這個模式呗巧妙地命名為外觀模式(Facade-Pattern),之是以這麼稱呼,是因為它将一個或數個類的複雜的一切都隐藏在背後,隻顯露出一個幹淨美好的外觀。

模式:                                                意圖:

裝飾者模式                                         不改變接口,但加入責任

擴充卡模式                                          将一個接口轉換成另外一個接口

外觀模式                                              讓接口更簡單

外觀沒有”封裝“子系統的類,外觀隻提供簡化的接口。是以客戶如果覺得有必要,依然可以直接使用子系統的類,這就是外觀模式的一個很好的特征:提供簡化的接口的同時,依然将系統完整的功能暴露出來,以供需要的人使用。

外觀模式:提供了一個統一的接口,用來通路子系統中的一群接口。外觀定義了一個高層接口,讓子系統更容易使用。

設計原則7:隻和你的密友談話。(最少知識原則)

這個原則希望我們在設計中,不要讓太多的類耦合在一起,免得修改系統中的一部分,會影響到其他的部分。如果許多類之間互相依賴,那麼這個系統就會變成一個易碎的系統,它需要花許多成本維護,也會因為太複雜而不容易被其他人了解。

這個原則提供了一些方針:

就任何對象而言,在該對象的方法類,我們隻應該調用屬于以下範圍的方法:

1.該對象本身

2.被當做方法的參數而傳遞進來的對象

3.此方法所建立活執行個體化的任何對象

4.對象的任何元件

10.模闆方法模式(封裝算法)

截止目前為止,我們以上的議題都是圍繞這封裝轉;我們已經封裝了對象,對象的建立,方法調用,複雜接口等,接下來我們要深入封裝算法塊,好讓子類可以在任何時候都可以将自己挂接進運算裡。

模闆方法模式:在一個方法中定義一個算法的骨架,而将一些步驟延遲到子類中。模闆方法使得子類可以在不改變算法結構的情況下,重新定義算法的某些步驟。

設計原則8:别調用(打電話給)我們,我們會調用(打電話給)你。這樣可以防止“依賴腐敗”的方法

模闆方式是一個常見的模式,到處都是,這個模式常見是因為對建立架構來說,這個模式簡直棒級了,有架構控制如果做事情,而由你(使用這個架構的人)指定架構算法中的每個步驟的細節。

11.疊代器與組合模式(管理良好的集合)

這個模式我的了解是:就是為了讓客戶周遊你的對象而又無法窺視你存取對象的方式;學習如何建立一些對象超集合(super collection),能夠一口氣就跳過某些讓人望而生畏的資料結構。

疊代器模式:提供一個方法順序通路一個聚合對象中的各個元素,而又不暴露其内部的表示。

當我面允許一個類不但要完成自己的事情(管理某種聚合),還要同時擔負更多的責任(例如周遊)時,我們就給了這個類兩個變化的原因,兩個?對!就是兩個:如果這個集合改變了話,這個類也必須改變;如果我們周遊的方式改變的話,這個類也必須跟着改變。

是以導緻了有如下的一個設計原則:

設計原則9:一個類應該隻有一個引起變化的原因。

【内聚(cohesion)這個術語你應該聽過,它用來度量一個類和子產品緊密地達到單一目的或責任。

    當一個子產品或者一個類被設計成隻支援一組相關功能時,我們說它具有高内聚;反之,當被設計成支援一組不相關的功能時,我們說它具有低 内聚。

内聚是】

12.組合模式

組合模式:允許你将對象組合成樹形結構來表現“整體/部分”才層次結構。組合能讓客戶以一緻的方式處理個别對象以及對象組合。

13.狀态模式(事物的狀态)

基本常識:政策模式和狀态模式是雙胞胎,在出生時才分開。

通過前面我們可以知道,政策模式是圍繞可以互換的算法來建立成功業務的。然而,狀态走的是更崇高的路,它通過改變對象内部的狀态來幫助對象控制自己的行為。

狀态模式:允許對象在内部狀态改變時改變它的行為,對象看起來好像修改了它的類。

這個模式将狀态封裝成獨立的類,并将動作委托到代表目前狀态的對象,我們知道行為會随内部狀态而改變。

14.代理模式(控制對象通路)

代理模式:為另一個對象提供一個替身或占位符以控制對這個對象的通路。

遠端代理是一般代理模式的一種實作。其實這個模式的變體相當多。

在真實的世界中,代理模式有許多變體,這些變體都有共同點:都會将客戶(subject)施加的方法調用攔截下來。

15.複合模式(模式的模式)

模式通常一起使用,并被組合在同一個設計解決方案中。

複合模式在一個解決方案中結合兩個或者多個模式,以解決一般或重複發生的問題。

MVC是一種範型!

鼎鼎大名的MVC(Model-View-Controller)就是一個真正的複合模式,它就是你的設計工具箱内最有威力的模式之一。

MVC是複合模式,結合了觀察者模式、政策模式群組合模式。

模型使用觀察者模式,以便觀察者更新,同時保持兩者之間解耦。

控制器是視圖的政策,視圖可以使用不同的控制器實作,得到不同的行為。

視圖使用組合模式實作使用者界面,使用者界面通常組合了嵌套的元件,像面闆、架構和按鈕。

這些模式攜手合作,把MVC模型的三層解耦,這樣可以保持幹淨又有彈性。

擴充卡模式用來将新的模式适配成已有的視圖和控制器。

Model 2是MVC在web上的應用,在Model 2中,控制器實作成Servlet,而JSP/HTML實作視圖。

組織設計模式

随着發掘的設計模式數目逐漸增加,有必要将它們分級,好将它們組織起來,以簡化我們尋找模式的過程,并讓同一群組内的模式互相比較。

在大多數的類目中,模式通常根據某種做法被歸為幾類哦。最廣為人知的分類方式,就是第一個模式類目中所采取的方式,根據模式的目标分成三個不同的類目:建立型、行為型和結構型。

建立型模式:涉及到将對象執行個體化,這類模式都提供一個方法,将客戶從所需要執行個體化的對象中解耦。

行為型模式:都涉及到類和對象如何互動及配置設定職責。

結構型模式可以讓你把類或對象組合到更大的結構中。

模式還有另外一種分類方式:模式所處理的是類還是對象。

類模式描述類之間的關系如何通過繼承定義。類模式的關系是在編譯時建立的。

對象模式描述對象之間的關系,而且主要是利用組合定義。對象模式的關系通常在運作時建立,而且更加動态、更有彈性。

我的了解:其實分類并不重要,分類隻是起友善我們記憶而已,重要的是了解這些模式和它們之間的關系。隻要類目有幫助,我們就用它,反正就不用。

最後就是 用模式去思考。。。。。呵呵。。。完畢!

再多說下,不要急切于使用模式,而是緻力于最能解決問題的簡單方案。

總結下:

模式:                                                       特點:

政策                                                             封裝可互換的行為,然後使用委托來決定要采用哪一個 行為

擴充卡                                                          改變一個或多個類看接口

疊代器                                                          提供一個方式來周遊集合,而無須暴露集合的實作

外觀                                                               簡化一群類的接口

組合                                                               客戶可以将對象的集合以及個别的對象一視同仁

觀察者                                                           當某個狀态改變時,允許一群對象能被通知到

工廠方法                                                      哪個具體類

模闆方法                                                     子類決定如果實作算法中的某些步驟

狀态                                                             封裝基于狀态的行為,并将行為委托到目前狀态 代理                                                              包裝對象,以控制對詞對象的通路 裝飾者                                                          包裝一個對象,以提供新的行為 觀察者                                                           讓對象能夠在狀态改變時被通知 組合                                                                客戶用一緻的方式處理對象集合和單個對象 單件                                                                 確定有且隻有一個對象被建立 抽象工廠                                                         允許客戶建立對象的家族,而無需指定他們的具體類

指令                                                                 封裝請求成為對象                                                        

繼續閱讀