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

yangdq發表於2020-07-15

設計模式是物件導向的最佳實踐(程式碼無錯未必優)

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

整體已維護,易複用,可擴充套件=》靈活度;

物件導向的好處:可維護,可擴充套件,可複用,靈活性好;

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

物件導向程式設計原則:開放封閉原則,依賴倒置原則;

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)運用共享技術有效的地支援大量細粒度的物件。

 

 

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

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

享元模式應用:

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

 

相關文章