­

【設計模式】設計模式(一)– 大話設計模式讀書筆記

設計模式是面向對象的最佳實踐(程式碼無錯未必優)

(適度封裝,合理繼承,結構多態)=》降耦合;

整體已維護,易復用,可擴展=》靈活度;

面向對象的好處:可維護,可擴展,可復用,靈活性好;

面向對象的標誌:依賴倒轉=》抽象不應該依賴細節,細節應該依賴於抽象=》程式中所有的依賴關係都終止於抽象類或者介面(對象之間的中間者);

面向對象編程原則:開放封閉原則,依賴倒置原則;

1.簡單工廠模式 factory(解決對象創建問題)–計算器,加功能

[工廠模式是定義一個擁有創建對象的介面,讓子類決定實例化哪一個類]

a、計算器,計算對象工廠

 

 

 2.策略者模式 strategy(策略:演算法,解決演算法創建,使演算法變化不影響演算法的客戶)–商場促銷

[策略模式是定義一系列演算法的方法,所有演算法完成相同的工作,以相同的方式調用所有的演算法,減少各種演算法類和使用演算法之間的耦合,分離演算法類簡化單元測試。策略模式封裝了變化規則-處理變化的可能性,及不同時間應用不同規則。]

a、收銀軟體(工廠+策略)

 

 

 3.抽象工廠模式 abstract factory — — DB更換

工廠方法模式是定義一個用於創建對象的介面,讓子類決定實例化哪一個類。

(提供一個創建一系列相關或互相依賴對應的介面,而無需指定他們具體的類)

a、資料庫實現更換

 

 

 抽象工廠模式(Abstract Factory),提供一個創建一系列相關或相互依賴對象的介面,而無需指定他們具體的類。工廠和產品都是抽象構成,抽象之間相互依賴,具體實現交給使用端控制。

抽象工廠模式的優缺點:

優點:a.易於交換產品系列,具體工廠類只需要初始化時出現一次,使得更改工廠非常容易。

b.讓具體的創建實例過程與客戶端分離,客戶端通過抽象介面操縱實例

缺點:a.增加抽象實現時對應需要修改的地方比較多,多次調用時遇變動需要修改的地方遞增

優化方案:反射+抽象工廠+配置文件(開放-封閉原則:對擴展開放,對修改關閉)

 

 

 從這個方面上來說:所有的用簡單工廠的地方,都可以用反射技術去除switch或if,解除耦合

4.單一職責原則 Single responsibility Principle –拍攝ufo

解釋:就一個類而言,應該只有一個引起它變化的原因。

例子:俄羅斯方塊的遊戲邏輯(數組操作)和介面渲染屬於不同的職責應該分開編寫。

在應用單一職責設計軟體時,應該發現職責並把那些職責相互分離。如果能想到多於一個的動機去改變一個類,那麼這個類就具有多於一個的職責。

編程時,要在類的職責分離上多思考,做到單一職責,這樣程式碼才能真正的易維護、易擴展、易復用、靈活多樣。

5.開放-封閉原則 The Open-Closed Principle –考研工作兩不誤

解釋:軟體實體(類、模組、函數等)應該可以擴展,但是不可修改。

面對需求,對程式的改動是通過增加新程式碼進行的,而不是更改現有的程式碼。

開放-封閉原則是面向對象設計的核心所在。遵循這個原則可以帶來面向對象技術所聲稱的巨大好處,也就是可維護、可擴展、可復用、靈活性好。開發人員應該僅對程式中呈現出頻繁變化的那部分做出抽象,然而,對於應用程式的每個部分都刻意的進行抽象同樣不是一個好主意。拒絕不成熟的抽象和抽象本省一樣重要。

6.依賴倒轉原則 –修電腦與修收音機

A.高層模組不應該依賴低層模組。兩個都應該依賴抽象。

B.抽象不應該依賴細節。細節應該依賴抽象。

7.里氏代換原則 –企鵝不能代換會飛的鳥類(不能復用)

子類型必須能夠替換它們的父類型。正是由於子類型的可替換性才使得父類型的模組在無需修改的情況下就可以擴展。

 

 

 依賴倒轉其實可以說是面向對象設計的標誌,用哪種語言來編寫程式不重要,如果編寫時考慮的都是如何針對抽象編程而不是針對細節編程,即程式中所有的依賴關係都是終止於抽象類或者介面,那就是面向對象設計,反之那就是過程化的設計了。

8.裝飾模式(Decorator)–穿什麼

動態的給一個對象添加一些額外的職責,就增加功能來說,裝飾模式比生成子類更為靈活。

 

 

 裝飾模式能有效的把類的核心職責和裝飾功能區分開,而且可以去除相關類中重複的裝飾邏輯。

9.代理模式(Proxy)–為別人做嫁衣,班長

為其他對象提供一種代理以控制對這個對象的訪問。

 

 

 代理模式應用:

a.遠程代理,也就是為一個對象在不同的地址空間提供局部代表。這樣可以隱藏一個對象存在於不同地址空間的事實。

b.虛擬代理,是根據需要創建開銷很大的對象。通過他來存放實例化需要很長時間的真實對象。(html圖片下載)

c.安全代理,用來控制真實對象訪問時的許可權。(用於對象有不同訪問許可權時)

d.智慧指引,是指當調用真實的對象時,代理處理另外一些事。

10.工廠方法模式(Factory Method)–學雷鋒,社區志願者類

定義一個用於創建對象的介面讓子類決定實例化哪一個類.工廠方法是一個類的實例化延遲到其子類。

 

 

 簡單工廠 VS 工廠方法

簡單工廠模式:的最大優點在於工廠類中包含了必要的邏輯判斷,根據客戶端的選擇條件動態實例化相關的類,對於客戶端來說,去除了與具體產品的依賴。

工廠方法模式:實現時,客戶端需要決定實例化哪一個工廠來實現運算類,選擇判斷的問題還是存在的,也就是說,工廠方法把簡單的工廠的內部邏輯判斷移到了客戶端程式碼來進行。想要加功能,本來是修改工廠類的,而現在是修改客戶端。

工廠方法客服了簡單工廠違背開放封閉原則的缺點,有保持了封裝對象創建過程的優點。集中封裝了對象的創建,使得要更換對象時,不需要做大的改動就可以實現,降低了客戶程式與產品對象的耦合。工廠方法模式是簡單工廠模式的進一步抽象和推廣。

11.原型模式(Prototype) –手寫簡歷,複印簡歷

用原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象。

 

 

 原型模式其實就是從一個對象再創建另外一個可訂製的對象,不需知道任何創建細節

它不用重新初始化對象,而是動態的獲得對象運行時的狀態

 

 

 java中實現方法

 

 

 淺複製vs深複製:

淺複製:被複制對象的所有變數都含有與原來的對象相同的值,而所有的對其他對象的引用仍然指向原來的對象。clone

深複製:把引用對象的變數指向複製過的新對象,而不是原有的被引用的對象。copy

 

 

 12.模板方法模式 — 考題抄錯會做也白搭

定義一個操作的演算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個演算法的結構即可重定義概演算法的某些特定步驟

當我們要完成在某細節層次一致的一個過程或一系列步驟,但其個別步驟在更詳細的層次上的實現可能不同時,我們通常考慮用模板方法模式來處理。使父類成為子類的模板,所有重複的程式碼要上升到父類去,而不是讓每個子類都去重複。

 

 

 當不變的和可變的行為在方法子類實現中混合在一起時,不變行為就會在子類中重複出現,通過模板方法模式把這些行為搬移到單一的地方,這樣就幫助子類擺脫重複的不變行為的糾纏。

13.迪米特法則(最小知識原則) –無熟人難辦事

如果兩個類不必彼此直接通訊,那麼這兩個類就不應當發生直接的相互作用。如果其中一個類需要調用另一個類的某一個方法的話,可以通過第三者轉發這個調用。

強調在類的結構設計上,每個類都應當盡量降低成員的訪問許可權。

迪米特法則其根本思想,是強調類之間的松耦合類之間的耦合越弱,越有利於復用,一個處於弱耦合的類被修改,不會對關係的類造成波及。

14.外觀模式(門面模式) –股票與基金經理人

外觀模式(Facade):為子系統的一組介面提供一個一致的介面,此模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。

 

 

 外觀模式的使用時機:

1.在設計初期階段,應該要有意識的將不同的兩個層分離,在層與層之間建立外觀Facade

2.在開發階段,子系統往往因為不斷的重構演化而變得越來越複雜,增加外觀Facade可以可提供一個簡單的介面,減少它們之間的依賴

3.在維護一個遺留的大型系統時,可能這個系統已經非常難以維護和擴展,但是新需求開發又必須依賴於它,可以為新系統開發一個外觀Facade類,來提供設計粗糙或高度複雜的遺留程式碼的比較清晰簡單的介面,讓新系統與Facade對象交互,Facade與遺留程式碼交互所有複雜的工作。

 

 

 15.建造者模式 –中餐味道不穩定,西餐味道穩定

將一個複雜對象的構建和它的表示分離,使得同樣的構建過程可以創建不同的表示。

使用時機:在創建複雜對象時和構建過程分離。

16.觀察者模式 –老闆回來,我不知道

觀察者模式又叫做發布-訂閱(Publish/Subscribe)模式

觀察者模式定義了一種一對多的依賴關係,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態發生變化時,會通知所有的觀察者對象,使它們能都自動更新自己。

 

 

 觀察者模式特點:

將系統分割成一系列分割成一系列互相協作的類有一個很不好的副作用,那就是需要維護相關對象間的一致性。我們不希望為了維持一致性而使各個類緊密耦合,這樣會給維護、擴展和重用都帶來不便。當一個對象的改變需要同時改變其他對象的時候適合使用觀察者模式。

觀察者模式所做的工作其實就是解除耦合。讓耦合的雙方都依賴於抽象,而不是依賴於具體。從而使得各自變化都不會影響另一邊的變化。

觀察者模式的不足:通知者和觀察者之間互相不知道,需要由客戶端來決定通知誰。

彌補觀察者模式的不足–事件委託機制:

委託就是一個引用方法的類型。一旦為委託分配了方法,委託將與該方法具有完全相同的行為。委託方法的使用可以像其他任何方法一樣,具有參數和返回值。委託可以看作是對函數的抽象,是函數『類』,委託的實例將代表一個具體的函數。一個委託可以搭載多個方法,所有方法被依次喚起。它可以使得委託對象對搭載的方法並不需要屬於同一個類。

委託的前提是委託對象所搭載的所有方法必須具有相同的原形和形式,也就是擁有相同的參數列表和返回值類型。

17.狀態模式

面向對象設計其實就是希望做到程式碼的責任分解。

狀態模式(state):當一個對象的內在狀態改變時允許改變其行為,這個對象看起來像是改變了其類。

狀態模式主要解決的是當控制一個對象狀態轉換的條件表達式過於複雜的情況。把狀態的判斷邏輯轉移到表示不同狀態的一系列類當中,可以把複雜的判斷邏輯簡化。

 

 

 好處:將與特定狀態相關的行為局部化,並且將不同狀態的行為分割開來。

將特定的狀態相關的行為都放入一個對象中,由於所有與狀態相關的程式碼都存在於某個ConcreteState中,所以通過定義新的子類可以很容易的增加新的狀態和轉換。消除龐大的條件分支語句,大的分支判斷會使得它們難以修改和擴展。狀態模式通過把各種狀態邏輯分布到state的子類之間,來減少相互的依賴。

用處:當一個對象的行為取決於它的狀態,並且它必須在運行時刻根據狀態改變它的行為時,就可以考慮使用狀態模式。

工作狀態-狀態模式:

 

 

 18.適配器模式 –電源適配器,姚明需要翻譯

適配器模式(Adapter),將一個類的介面轉換成客戶希望的另一個介面。Adapter模式使得原本由於介面不能兼容而不能一起工作的那些類可以一起工作。

軟體開發中,系統的數據和行為都正確,但介面不符時,我們應該考慮用適配器,目的是使控制範圍之外的一個原有對象與某個介面匹配。適配器模式主要應用於希望復用一些現存的類,但是介面又與復用環境要求不一致的情況。

 

 

 球員適配器:

 

 

 19.備忘錄模式

備忘錄(Memento):在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象之外保存這個狀態。這樣以後就可將該對象恢復到原先保存的狀態。

 

 

 將要保存的細節封裝到Memento中,哪一天要更改保存的細節也不用影響客戶端。

Menento模式比較使用於功能比較複雜的,但需要維護或記錄屬性歷史的類,或者需要保存的屬性只是眾多屬性中的一小部分中,Originator可以根據保存的Menento資訊還原到前一狀態。使用備忘錄可以把複雜的對象內部資訊對其他的對象屏蔽起來,恰當的封裝邊界。

遊戲備忘錄:

 

 

 20.迭代器模式 — 上車買票

迭代器模式(Iterator),提供一種方法順序訪問一個聚合對象中各個元素,而又不暴露該對象的內部表示。

需要訪問全部聚焦對象,需要聚焦有多種方式遍歷,為不同的聚集結構提供如開始、下一個、是否結束、當前哪一項等統一的介面。

 

 

 迭代器模式就是分離了集合對象的遍歷行為,抽象出一個迭代器來負責,這樣既可以做到不暴露集合的內部結構,又可以讓外部程式碼透明地訪問集合內部的數據。

21.單例模式 — 有些類也需要計劃生育

單例模式Singleton:保證一個類僅有一個實例,並提供一個訪問它的全家訪問點。

通常我們可以讓一個全局變數使得一個對象被訪問,但它不能防止你實例化多個對象。一個最好的辦法就是,讓類自身負責保存它的唯一實例。這個類可以保證沒有其他實例可以被創建,並且它可以提供一個 訪問該實例的方法。

所有類都有構造方法,不編碼則系統默認生成空的構造方法,若有顯示定義的構造方法,默認的構造方法就會失效。

 

 

 好處:單例模式因為Singleton類封裝它的唯一實例,這樣它可以嚴格地控制客戶怎樣訪問它以及何時訪問它,簡單地說就是對唯一實例的受控訪問。

多執行緒時的單例:(並發訪問時可能會造成創建多個實例)

可以給進程一把鎖來處理,lock確保當一個執行緒位於程式碼的臨界區時,另一個執行緒進入臨界區。如果其他執行緒視圖進入鎖定的程式碼,則它將一直等待(即被阻止),直到該對象被釋放。

懶漢初始化:

 

 

 雙重鎖定:double-check-locking

 

 

 餓漢模式:靜態初始化-類載入時初始化

 

 

 22.合成/聚合復用原則(CARP)– 松耦合

合併/聚合復用原則:盡量使用合成/聚合,盡量不要使用類繼承。

合成(Composition)和聚合(Aggrega)都是關聯的特殊種類。聚合表示一種」擁有「關係,體現的是A對象可以包含B對象,但是B對象不是A對象的一部分合成則是一種」擁有「關係,體現了嚴格的部分和整體的關係,部分和整體的生命周期一樣。例如大雁和翅膀的關係是合成,大雁和雁群的關係是聚合。

 

 

 合成/聚合復用原則的好處是,優先使用對象合成/聚合將有助於你保持每個類被封裝,並被集中在的單個任務上。這樣類和類繼承層次會保持較小規模,並且不太可能增長為不可控制的龐然大物。

對象的繼承關係時在編譯時就定義好了,所以無法在運行時改變從父類繼承的實現。子類的實現與它的父類有非常緊密的依賴關係,以至於父類實現中的任何變化必然會導致子類發生變化。當你需要復用子類時,如果繼承下來的實現不適合解決新問題,則父類必須重寫或被其他更合適的類替換。這種依賴關係限制了靈活性並最終限制了復用性。

優先使用對象的合成或聚合,而不是類繼承。合成/聚合更加松耦合。

22.橋接模式 — 手機軟體何時統一

橋接模式(Bridge),將抽象部分與它的實現部分分離,使它們都可以獨立地變化。

抽象與它地實現分離,並不是說,讓抽象類與其派生類分離,因為這沒有任何意義。實現指的是抽象類和它地派生類用來實現自己地對象。

 

 

 實現系統可能有多角度分類,每一種分類都有可能變化,那麼就把這種多角度分離出來讓它們獨立變化,減少他們之間的耦合。

只要正真深入理解了設計原則,很多設計模式其實就是原則的應用而已,或許在不知不覺中就在使用設計模式了!

23.命令模式 — 烤羊肉串的緊耦合

行為請求者與行為實現者的緊耦合存在很多隱患

命令模式(Command),將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日誌,以及支援可撤銷操作。

 

 

 例如烤肉店運用命令模式

 

 

 命令模式作用:

第一:它能較容易地設計一個命令隊列;

第二:在需要地情況下,可以較容易地將命令記入日誌;

第三:允許接收請求地一方決定是否要否決請求;

第四:可以容易地實現對請求地撤銷和重做;

第五:由於加進新的具體命令類不影響其他的類,因此增加新的具體命令類很容易;

命令模式把請求一個操作的對象與知道怎麼執行一個操作的對象分割

敏捷開發原則告訴我們,不要為程式碼添加基於猜測的、實際不需要的功能。如果不清楚一個系統是否需要命令模式,一般就不要著急去實現它,事實上,在需要的時候通過重構實現這個模式並不困難,只有在真正需要如撤銷/恢復操作等功能時,把原來的程式碼重構為命令模式才有意義。

24.責任鏈模式 — 加新非要老總批?

如果涉及的的處理流程太多,全部寫在一個分支裡面,一個類責任太多。違背了單一職責原則與開放封閉原則。

責任鏈模式(Chain of Responsibility):使多個對象都有機會處理請求,從而避免請求得發送者和接受者之間得耦合關係。將這些對象連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個對象處理它為止。

 

 

 責任鏈的好處:當客戶提交一個請求時,請求是沿鏈傳遞直至有一個ConcreteHandler對象負責處理它。

接受者和發送者都沒有對方的明確資訊,且鏈中的對象自己也並不知道鏈的結構。結果是職責鏈可簡化對象的相互連接,它們僅需保持一個指向其後繼者的引用,而不需保持它們所有的候選接受者的引用,這就極大降低了耦合度。也可以隨時增加或修改處理一個請求的結構。增強了給對象指派職責的靈活性。需要注意是一個請求可能到了鏈末端都得不到處理,或者因為沒有正確配置而得不到處理。

25.中介者模式 — 世界需要和平,聯合國

將一個系統分割成許多對象通常可以增加其可復用性,但是對象間相互連接的激增又會降低其可復用性。大量連接使得一個對象不可能在沒有其他對象的支援下工作,系統表現為一個不可分割的整體,所以,對系統的行為進行任何較大的改動就十分困難了。

中介者模式(Mediator)用一個中介對象來封裝一系列的對象交互。中介者使各個對象不需要顯式地互相引用,從而使其耦合鬆散,而且可以獨立地改變它們之間地交互。

 

 

 中介者模式優缺點:

中介者模式很容易在系統中應用,也很容易在系統中誤用。當系統出現『多對多』交互複雜地對象群時,不要急於使用中介者模式,而要先反思你地系統在設計上是不是合理。

Mediator的出現減少了各個Colleague的耦合,使得可以獨立地改變和復用各個Colleague類和Mediator。由於把對象如何協作進行了抽象,將中介作為一個獨立地概念並將其封裝在一個對象中,這樣關注地對象就從對象各自本身的行為轉移到它們之間的交互上來,也就是站在一個更宏觀的角度去看待系統。

中介者可能會因為交互對象越來越多變得非常複雜,由於ConcreteMediator控制了集中化,於是就把交互複雜性變成了中介的複雜性,這就使得中介者會變得比任何一個ConcreteColleague都複雜。

典型中介者模式:計算器程式,所有控制項得交互都是由Form窗體來作中介,操作各個對象。

中介者模式一般應用於一組對象以定義良好但是複雜的方式進行通訊的場合,以及想訂製一個分布在多個類中的行為,而又不想生成太多的子類的場合。

26.享元模式 — 項目多也別傻做

享元模式(Flyweight)運用共享技術有效的地支援大量細粒度的對象。

 

 

 在享元對象內部並不會隨環境的改變而改變的共享部分,可以稱為享元對象的內部狀態,而隨環境改變而改變的、不可以共享的狀態就是外部狀態。

享元模式可以避免大量非常相似類的開銷。在程式設計中,有時需要生成大量細粒度的類實例來表示數據。如果能發現這些實例除了幾個參數外基本都是相同的,有時就能夠受大幅度地減少需要實例化的類的數量。如果能把那些參數移到類實例的外面,在方法調用時將它們傳遞進來,就可以通過共享大幅度地減少單個實例地數目

享元模式應用:

如果一個應用程式使用了大量地對象,而大量的這些對象造成了很大的存儲開銷時就應該考慮使用;還有就是對象的大多數狀態可以是外部狀態,如果刪除對象的外部狀態,那麼可以用相對較少的共享對象取代很多組對象,此時可以考慮使用享元模式。