一、設計模式總述:
1、什么是設計模式:
設計模式是一套經過反復使用的代碼設計經驗,目的是為了重用代碼、讓代碼更容易被他人理解、保證代碼可靠性, 設計模式于己于人于系統都是多贏的,它使得代碼撰寫真正工程化,它是軟體工程的基石,如同大廈的一塊塊磚石一樣,專案中合理的運用設計模式可以完美的解決很多問題,每種模式在現實中都有相應的原理來與之對應,每種模式描述了一個在我們周圍不斷重復發生的問題,以及該問題的核心解決方案,這也是它能被廣泛應用的原因,總體來說,設計模式分為三大類:
- 創建型模式:共5種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式
- 結構型模式:共7種:配接器模式、裝飾器模式、代理模式、橋接模式、外觀模式、組合模式、享元模式
- 行為型模式:共11種:策略模式、模板方法模式、觀察者模式、責任鏈模式、訪問者模式、中介者模式、迭代器模式、命令模式、狀態模式、備忘錄模式、解釋器模式
其實還有兩類:并發型模式和執行緒池模式,用一個圖片來整體描述一下:

2、設計模式的六大原則:
(1)開閉原則 (Open Close Principle) :
開閉原則指的是對擴展開放,對修改關閉,在對程式進行擴展的時候,不能去修改原有的代碼,想要達到這樣的效果,我們就需要使用介面或者抽象類
(2)依賴倒轉原則 (Dependence Inversion Principle):
依賴倒置原則是開閉原則的基礎,指的是針對介面編程,依賴于抽象而不依賴于具體
(3)里氏替換原則 (Liskov Substitution Principle) :
里氏替換原則是繼承與復用的基石,只有當子類可以替換掉基類,且系統的功能不受影響時,基類才能被復用,而子類也能夠在基礎類上增加新的行為,所以里氏替換原則指的是任何基類可以出現的地方,子類一定可以出現,
里氏替換原則是對 “開閉原則” 的補充,實作 “開閉原則” 的關鍵步驟就是抽象化,而基類與子類的繼承關系就是抽象化的具體實作,所以里氏替換原則是對實作抽象化的具體步驟的規范,
(4)介面隔離原則 (Interface Segregation Principle):
使用多個隔離的介面,比使用單個介面要好,降低介面之間的耦合度與依賴,方便升級和維護方便
(5)迪米特原則 (Demeter Principle):
迪米特原則,也叫最少知道原則,指的是一個類應當盡量減少與其他物體進行相互作用,使得系統功能模塊相對獨立,降低耦合關系,該原則的初衷是降低類的耦合,雖然可以避免與非直接的類通信,但是要通信,就必然會通過一個“中介”來發生關系,過分的使用迪米特原則,會產生大量的中介和傳遞類,導致系統復雜度變大,所以采用迪米特法則時要反復權衡,既要做到結構清晰,又要高內聚低耦合,
(6)合成復用原則 (Composite Reuse Principle):
盡量使用組合/聚合的方式,而不是使用繼承,
二、Java的23種設計模式:
接下來我們詳細介紹Java中23種設計模式的概念,應用場景等情況,并結合他們的特點及設計模式的原則進行分析
1、創建型-工廠方法模式:
工廠方法模式分為三種:
(1)簡單工廠模式:
建立一個工廠類,并定義一個介面對實作了同一介面的產品類進行創建,首先看下關系圖:

(2)工廠方法模式:
工廠方法模式是對簡單工廠模式的改進,簡單工廠的缺陷在于不符合“開閉原則”,每次添加新產品類就需要修改工廠類,不利于系統的擴展維護,而工廠方法將工廠抽象化,并定義一個創建物件的介面,每增加新產品,只需增加該產品以及對應的具體實作工廠類,由具體工廠類決定要實體化的產品是哪個,將物件的創建與實體化延遲到子類,這樣工廠的設計就符合“開閉原則”了,擴展時不必去修改原來的代碼,UML關系圖如下:

(3)靜態工廠方法模式:
靜態工廠模式是將工廠方法模式里的方法置為靜態的,不需要創建實體,直接呼叫即可,
工廠方法模式詳情文章:Java設計模式之創建型:工廠模式詳解(簡單工廠+工廠方法+抽象工廠)
2、創建型-抽象工廠模式:
抽象工廠模式主要用于創建相關物件的家族,當一個產品族中需要被設計在一起作業時,通過抽象工廠模式,能夠保證客戶端始終只使用同一個產品族中的物件;并且通過隔離具體類的生成,使得客戶端不需要明確指定具體生成類;所有的具體工廠都實作了抽象工廠中定義的公共介面,因此只需要改變具體工廠的實體,就可以在某種程度上改變整個軟體系統的行為,
但該模式的缺點在于添加新的行為時比較麻煩,如果需要添加一個新產品族物件時,需要更改介面及其下所有子類,這必然會帶來很大的麻煩,
UML結構圖如下:

抽象工廠模式詳情:Java設計模式之創建型:工廠模式詳解(簡單工廠+工廠方法+抽象工廠)
3、創建型-建造者模式:
建造者模式將復雜產品的創建步驟分解在在不同的方法中,使得創建程序更加清晰,從而更精確控制復雜物件的產生程序;通過隔離復雜物件的構建與使用,也就是將產品的創建與產品本身分離開來,使得同樣的構建程序可以創建不同的物件;并且每個具體建造者都相互獨立,因此可以很方便地替換具體建造者或增加新的具體建造者,用戶使用不同的具體建造者即可得到不同的產品物件,UML結構圖如下:

建造者模式詳情:Java設計模式之創建型:建造者模式
4、創建型-單例模式:
單例模式可以確保系統中某個類只有一個實體,該類自行實體化并向整個系統提供這個實體的公共訪問點,除了該公共訪問點,不能通過其他途徑訪問該實體,單例模式的優點在于:
- 系統中只存在一個共用的實體物件,無需頻繁創建和銷毀物件,節約了系統資源,提高系統的性能
- 可以嚴格控制客戶怎么樣以及何時訪問單例物件,
單例模式的寫法有好幾種,主要有三種:懶漢式單例、餓漢式單例、登記式單例,
單例模式詳情:Java設計模式之創建型:單例模式
5、創建型-原型模式:
原型模式也是用于物件的創建,通過將一個物件作為原型,對其進行復制克隆,產生一個與源物件類似的新物件,UML類圖如下:

在 Java 中,原型模式的核心是就是原型類 Prototype,Prototype 類需要具備以下兩個條件:
- 實作 Cloneable 介面:
- 重寫 Object 類中的 clone() 方法,用于回傳物件的拷貝;
Object 類中的 clone() 方法默認是淺拷貝,如果想要深拷貝物件,則需要在 clone() 方法中自定義自己的復制邏輯,
- 淺復制:將一個物件復制后,基本資料型別的變數會重新創建,而參考型別指向的還是原物件所指向的記憶體地址,
- 深復制:將一個物件復制后,不論是基本資料型別還有參考型別,都是重新創建的,
使用原型模式進行創建物件不僅簡化物件的創建步驟,還比 new 方式創建物件的性能要好的多,因為 Object 類的 clone() 方法是一個本地方法,直接操作記憶體中的二進制流,特別是復制大物件時,性能的差別非常明顯;
原型模式詳情:Java設計模式之創建型:原型模式
上面我們介紹了5種創建型模式,下面我們就開始介紹下7種結構型模式:配接器模式、裝飾模式、代理模式、外觀模式、橋接模式、組合模式、享元模式,其中物件的配接器模式是各種模式的起源,如下圖:

6、結構型-配接器模式:
配接器模式主要用于將一個類或者介面轉化成客戶端希望的格式,使得原本不兼容的類可以在一起作業,將目標類和適配者類解耦;同時也符合“開閉原則”,可以在不修改原代碼的基礎上增加新的配接器類;將具體的實作封裝在適配者類中,對于客戶端類來說是透明的,而且提高了適配者的復用性,但是缺點在于更換配接器的實作程序比較復雜,
所以,配接器模式比較適合以下場景:
- (1)系統需要使用現有的類,而這些類的介面不符合系統的介面,
- (2)使用第三方組件,組件介面定義和自己定義的不同,不希望修改自己的介面,但是要使用第三方組件介面的功能,
下面有個非常形象的例子很好地說明了什么是配接器模式:

配接器模式的主要實作有三種:類的配接器模式、物件的配接器模式、介面的配接器模式,三者的使用場景如下:
- 類的配接器模式:當希望將一個類轉換成滿足另一個新介面的類時,可以使用類的配接器模式,創建一個新類,繼承原有的類,實作新的介面即可,
- 物件的配接器模式:當希望將一個物件轉換成滿足另一個新介面的物件時,可以創建一個Wrapper類,持有原類的一個實體,在Wrapper類的方法中,呼叫實體的方法就行,
- 介面的配接器模式:當不希望實作一個介面中所有的方法時,可以創建一個抽象類Wrapper,實作所有方法,我們寫別的類的時候,繼承抽象類即可,
配接器模式詳情:Java設計模式之結構型:配接器模式
7、結構型-裝飾器模式:
裝飾器模式可以動態給物件添加一些額外的職責從而實作功能的拓展,在運行時選擇不同的裝飾器,從而實作不同的行為;比使用繼承更加靈活,通過對不同的裝飾類進行排列組合,創造出很多不同行為,得到功能更為強大的物件;符合“開閉原則”,被裝飾類與裝飾類獨立變化,用戶可以根據需要增加新的裝飾類和被裝飾類,在使用時再對其進行組合,原有代碼無須改變,裝飾器模式的UML結構圖如下:

但是裝飾器模式也存在缺點,首先會產生很多的小物件,增加了系統的復雜性,第二是排錯比較困難,對于多次裝飾的物件,除錯時尋找錯誤可能需要逐級排查,較為煩瑣,
裝飾器模式詳情:Java設計模式之結構型:裝飾器模式
8、結構型-代理模式:
代理模式的設計動機是通過代理物件來訪問真實物件,通過建立一個物件代理類,由代理物件控制原物件的參考,從而實作對真實物件的操作,在代理模式中,代理物件主要起到一個中介的作用,用于協調與連接呼叫者(即客戶端)和被呼叫者(即目標物件),在一定程度上降低了系統的耦合度,同時也保護了目標物件,但缺點是在呼叫者與被呼叫者之間增加了代理物件,可能會造成請求的處理速度變慢,UML結構圖如下:

代理模式詳情:Java設計模式之結構型:代理模式
9、結構型-橋接模式:
橋接模式將系統的抽象部分與實作部分分離解耦,使他們可以獨立的變化,為了達到讓抽象部分和實作部分獨立變化的目的,橋接模式使用組合關系來代替繼承關系,抽象部分擁有實作部分的介面物件,從而能夠通過這個介面物件來呼叫具體實作部分的功能,也就是說,橋接模式中的橋接是一個單方向的關系,只能夠抽象部分去使用實作部分的物件,而不能反過來,
橋接模式符合“開閉原則”,提高了系統的可拓展性,在兩個變化維度中任意擴展一個維度,都不需要修改原來的系統;并且實作細節對客戶不透明,可以隱藏實作細節,但是由于聚合關系建立在抽象層,要求開發者針對抽象進行編程,這增加系統的理解和設計難度,橋接模式的UML結構圖如下:

就像在Java中我們使用 JDBC 連接資料庫時,在各個資料庫之間進行切換,基本不需要動太多的代碼,原因就是使用了橋接模式,JDBC 提供統一介面,每個資料庫提供各自的實作,然后由橋接類創建一個連接資料庫的驅動,使用某一個資料庫的時候只需要切換一下就行,JDBC 的結構圖如下:

在 JDBC 中,橋接模式的實作化角色 (Implementor) 為的 Driver 介面,具體實作化 (Concrete Implementor) 角色對應 MysqlDriver、OracleDriver 和 MariadbDriver,擴展抽象化 (Refined Abstraction) 角色對應 DriverManager,不具有抽象化 (Abstraction) 角色作為擴展抽象化角色的父類,
橋接模式詳情:Java設計模式之結構型:橋接模式
10、結構型-外觀模式:
外觀模式通過對客戶端提供一個統一的介面,用于訪問子系統中的一群介面,使用外觀模式有以下幾點好處:
(1)更加易用:使得子系統更加易用,客戶端不再需要了解子系統內部的實作,也不需要跟眾多子系統內部的模塊進行互動,只需要跟外觀類互動就可以了;
(2)松散耦合:將客戶端與子系統解耦,讓子系統內部的模塊能更容易擴展和維護,
(3)更好的劃分訪問層次:通過合理使用 Facade,可以更好地劃分訪問的層次,有些方法是對系統外的,有些方法是系統內部使用的,把需要暴露給外部的功能集中到門面中,這樣既方便客戶端使用,也很好地隱藏了內部的細節,
但是如果外觀模式對子系統類做太多的限制則減少了可變性和靈活性,所以外觀模式適用于為復雜子系統提供一個簡單介面,提高系統的易用性場景 以及 引入外觀模式將子系統與客戶端進行解耦,提高子系統的獨立性和可移植性,
外觀模式的UML結構圖如下:

外觀模式詳情: Java設計模式之結構型:外觀模式
11、結構型-組合模式:
組合模式將葉子物件和容器物件進行遞回組合,形成樹形結構以表示“部分-整體”的層次結構,使得用戶對單個物件和組合物件的使用具有一致性,能夠像處理葉子物件一樣來處理組合物件,無需進行區分,從而使用戶程式能夠與復雜元素的內部結構進行解耦,
組合模式最關鍵的地方是葉子物件和組合物件實作了相同的抽象構建類,它既可表示葉子物件,也可表示容器物件,客戶僅僅需要針對這個抽象構建類進行編程,這就是組合模式能夠將葉子節點和物件節點進行一致處理的原因,組合模式的UML結構圖如下:

組合模式詳情: Java設計模式之結構型:組合模式
12、結構型-享元模式:
享元模式通過共享技術有效地支持細粒度、狀態變化小的物件復用,當系統中存在有多個相同的物件,那么只共享一份,不必每個都去實體化一個物件,極大地減少系統中物件的數量,從而節省資源,
享元模式的核心是享元工廠類,享元工廠類維護了一個物件存盤池,當客戶端需要物件時,首先從享元池中獲取,如果享元池中存在物件實體則直接回傳,如果享元池中不存在,則創建一個新的享元物件實體回傳給用戶,并在享元池中保存該新增物件,這點有些單例的意思,
工廠類通常會使用集合型別來保存物件,如 HashMap、Hashtable、Vector 等等,在 Java 中,資料庫連接池、執行緒池等都是用享元模式的應用,
享元模式的UML結構圖如下:

Java 中,String 型別就是使用享元模式,String 物件是 final 型別,物件一旦創建就不可改變,而 Java 的字串常量都是存在字串常量池中的,JVM 會確保一個字串常量在常量池中只有一個拷貝,
而且提到共享池,我們也很容易聯想到 Java 里面的JDBC連接池,通過連接池的管理,實作了資料庫連接的共享,不需要每一次都重新創建連接,節省了資料庫重新創建的開銷,提升了系統的性能!
享元模式詳情:Java設計模式之結構型:享元模式
前面我們介紹了7種結構型設計模式,接下來我們介紹一下11種行為型設計模式:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式,先來張圖,看看這11中模式的關系:

13、行為型-策略模式:
將類中經常改變或者可能改變的部分提取為作為一個抽象策略介面類,然后在類中包含這個物件的實體,這樣類實體在運行時就可以隨意呼叫實作了這個介面的類的行為,
比如定義一系列的演算法,把每一個演算法封裝起來,并且使它們可相互替換,使得演算法可獨立于使用它的客戶而變化,這就是策略模式,UML結構圖如下:

策略模式的優點在于可以動態改變物件的行為;但缺點是會產生很多策略類,并且策略模式的決定權在用戶,系統只是提供不同演算法的實作,所以客戶端必須知道所有的策略類,并自行決定使用哪一個策略類;
策略模式適用用于以下幾種場景:
- (1)應用程式需要實作特定的功能服務,而該程式有多種實作方式使用,所以需要動態地在幾種演算法中選擇一種
- (2)一個類定義了多種行為演算法,并且這些行為在類的操作中以多個條件陳述句的形式出現,就可以將相關的條件分支移入它們各自的Strategy類中以代替這些條件陳述句,
策略模式詳情:Java設計模式之行為型:策略模式
14、行為型-模板方法:
模板方法是基于繼承實作的,在抽象父類中宣告一個模板方法,并在模板方法中定義演算法的執行步驟(即演算法骨架),在模板方法模式中,可以將子類共性的部分放在父類中實作,而特性的部分延遲到子類中實作,只需將特性部分在父類中宣告成抽象方法即可,使得子類可以在不改變演算法結構的情況下,重新定義演算法中的某些步驟,不同的子類可以以不同的方式來實作這些邏輯,
模板方法模式的優點在于符合“開閉原則”,也能夠實作代碼復用,將不變的行為轉移到父類,去除子類中的重復代碼,但是缺點是不同的實作都需要定義一個子類,導致類的個數的增加使得系統更加龐大,設計更加抽象,模板方法模式的UML圖如下:

模板方法詳情:Java設計模式之行為型:模板方法模式
15、行為型-責任鏈模式:
職責鏈可以將請求的處理者組織成一條鏈,并將請求沿著鏈傳遞,如果某個處理者能夠處理請求則處理,否則將該請求交由上級處理,客戶端只需將請求發送到職責鏈上,無須關注請求的處理細節,通過職責鏈將請求的發送者和處理者解耦了,這也是職責鏈的設計動機,
職責鏈模式可以簡化物件間的相互連接,因為客戶端和處理者都沒有對方明確的資訊,同時處理者也不知道職責鏈中的結構,處理者只需保存一個指向后續者的參考,而不需要保存所有候選者的參考,
另外職責鏈模式增加了系統的靈活性,我們可以任意增加或更改處理者,甚至更改處理者的順序,不過有可能會導致一個請求無論如何也得不到處理,因為它可能被放置在鏈末端,
所以責任鏈模式有以下幾個優點:
- (1)降低耦合度,將請求的發送者和接收者解耦,反映在代碼上就是不需要在類中寫很多丑陋的 if….else 陳述句,如果用了職責鏈,相當于我們面對一個黑箱,只需將請求遞交給其中一個處理者,然后讓黑箱內部去負責傳遞就可以了,
- (2)簡化了物件,使得物件不需要鏈的結構,
- (3)增加系統的靈活性,通過改變鏈內的成員或者調動他們的次序,允許動態地新增或者洗掉處理者
- (4)增加新的請求處理類很方便,
但是責任鏈模式也存在一些缺點:
- (1)不能保證請求一定被成功處理
- (2)系統性能將受到一定影響,并且可能會造成回圈呼叫,
- (3)可能不容易觀察運行時的特征,而且在進行代碼除錯時不太方便,有礙于除錯,
責任鏈模式的UML結構圖如下:

責任鏈模式詳情:Java設計模式之行為型:責任鏈模式
16、行為型-觀察者模式:
觀察者模式又稱為 發布-訂閱模式,定義了物件之間一對多依賴關系,當目標物件(被觀察者)的狀態發生改變時,它的所有依賴者(觀察者)都會收到通知,一個觀察目標可以對應多個觀察者,而這些觀察者之間沒有相互聯系,所以能夠根據需要增加和洗掉觀察者,使得系統更易于擴展,符合開閉原則;并且觀察者模式讓目標物件和觀察者松耦合,雖然彼此不清楚對方的細節,但依然可以互動,目標物件只知道一個具體的觀察者串列,但并不認識任何一個具體的觀察者,它只知道他們都有一個共同的介面,
但觀察者模式的缺點在于如果存在很多個被觀察者的話,那么將需要花費一定時間通知所有的觀察者,如果觀察者與被觀察者之間存在回圈依賴的話,那么可能導致系統崩潰,并且觀察者模式沒有相應的機制讓觀察者知道被觀察物件是怎么發生變化的,而僅僅只是知道觀察目標發生了變化,觀察者模式的UML結構圖如下:

觀察者模式詳情:Java設計模式之行為型:觀察者模式
17、行為型-訪問者模式:
訪問者模式就是一種分離物件資料結構與行為 (基于資料結構的操作) 的方法,通過這種分離,達到為一個被訪問者動態添加新的操作而無需做其它修改的效果,使得添加作用于這些資料結構的新操作變得簡單,并且不需要改變各資料結構,為不同型別的資料結構提供多種訪問操作方式,這樣是訪問者模式的設計動機,
除了使新增訪問操作變得更加簡單,也能夠在不修改現有類的層次結構下,定義該類層次結構的操作,并將有關元素物件的訪問行為集中到一個訪問者物件中,而不是分散搞一個個的元素類中,
但訪問者模式的缺點在于讓增加新的元素類變得困難,每增加一個新的元素類都意味著要在抽象訪問者角色中增加一個新的抽象操作,并在每一個具體訪問者類中增加相應的具體操作,違背了“開閉原則”的要求;
所以訪問者模式適用于物件結構中很少改變,但經常需要在此物件結構上定義新的操作的系統,使得演算法操作的增加變得簡單;或者需要對一個物件結構中進行很多不同并且不相關的操作,并且需要避免讓這些操作污染這些物件,也不希望在增加新操作時修改這些類的場景,
訪問者模式的UML結構圖如下:

從上面的 UML 結構圖中我們可以看出,訪問者模式主要分為兩個層次結構,一個是訪問者層次結構,提供了抽象訪問者和具體訪問者,主要用于宣告一些操作;一個是元素層次結構,提供了抽象元素和具體元素,主要用于宣告 accept 操作;而物件結構 ObjectStructure 作為兩者的橋梁,存盤了不同型別的物件,以便不同的訪問者來訪問,相同訪問者可以以不同的方式訪問不同的元素,所以在訪問者模式中增加新的訪問者無需修改現有代碼,可擴展行強,
在訪問者模式使用了雙分派技術,所謂雙分派技術就是在選擇方法的時候,不僅僅要根據訊息接收者的運行時區別,還要根據引數的運行時區別,在訪問者模式中,客戶端將具體狀態當做引數傳遞給具體訪問者,這里完成第一次分派,然后具體訪問者作為引數的“具體狀態”中的方法,同時也將自己this作為引數傳遞進去,這里就完成了第二次分派,雙分派意味著得到的執行操作決定于請求的種類和接受者的型別,
訪問者模式詳情:Java設計模式之行為型:訪問者模式
18、行為型-中介者模式:
中介者模式通過中介者物件來封裝一系列的物件互動,將物件間復雜的關系網狀結構變成結構簡單的以中介者為核心的星形結構,物件間一對多的關聯轉變為一對一的關聯,簡化物件間的關系,便于理解;各個物件之間的關系被解耦,每個物件不再和它關聯的物件直接發生相互作用,而是通過中介者物件來與關聯的物件進行通訊,使得物件可以相對獨立地使用,提高了物件的可復用和系統的可擴展性,
在中介者模式中,中介者類處于核心地位,它封裝了系統中所有物件類之間的關系,除了簡化物件間的關系,還可以對物件間的互動進行進一步的控制,中介者模式的UML結構圖如下:

但是,中介者物件封裝了物件之間的關聯關系,導致中介者物件變得比較龐大復雜,所承擔的責任也比較多,維護起來也比較困難,它需要知道每個物件和他們之間的互動細節,如果它出問題,將會導致整個系統都會出問題,
中介者模式詳情:Java設計模式之行為型:中介者模式
19、行為型-命令模式:
命令模式的本質是將請求封裝成物件,將發出命令與執行命令的責任分開,命令的發送者和接收者完全解耦,發送者只需知道如何發送命令,不需要關心命令是如何實作的,甚至是否執行成功都不需要理會,命令模式的關鍵在于引入了抽象命令介面,發送者針對抽象命令介面編程,只有實作了抽象命令介面的具體命令才能與接收者相關聯,
使用命令模式的優勢在于降低了系統的耦合度,而且新命令可以很方便添加到系統中,也容易設計一個組合命令,但缺點在于會導致某些系統有過多的具體命令類,因為針對每一個命令都需要設計一個具體命令類,
命令模式的UML結構圖如下:

命令模式詳情: Java設計模式之行為型:命令模式
20、行為型-狀態模式:
狀態模式,就是允許物件在內部狀態發生改變時改變它的行為,物件看起來就好像修改了它的類,也就是說以狀態為原子來改變它的行為,而不是通過行為來改變狀態,
當物件的行為取決于它的屬性時,我們稱這些屬性為狀態,那該物件就稱為狀態物件,對于狀態物件而言,它的行為依賴于它的狀態,比如要預訂房間,只有當該房間空閑時才能預訂,想入住該房間也只有當你預訂了該房間或者該房間為空閑時,對于這樣的一個物件,當它的外部事件產生互動的時候,其內部狀態就會發生變化,從而使得他的行為也隨之發生變化,
狀態模式的UML結構圖如下:

從上面的UML結構圖我們可以看出狀態模式的優點在于:
(1)封裝了轉換規則,允許狀態轉換邏輯與狀態物件合成一體,而不是某一個巨大的條件陳述句塊
(2)將所有與狀態有關的行為放到一個類中,可以方便地增加新的狀態,只需要改變物件狀態即可改變物件的行為,
但是狀態模式的缺點在于:
(1)需要在列舉狀態之前需要確定狀態種類
(2)會導致增加系統類和物件的個數,
(3)對 “開閉原則” 的支持并不友好,新增狀態類需要修改那些負責狀態轉換的源代碼,否則無法切換到新增狀態;而且修改某個狀態類的行為也需修改對應類的源代碼,
所以狀態模式適用于:代碼中包含大量與物件狀態有關的條件陳述句,以及物件的行為依賴于它的狀態,并且可以根據它的狀態改變而改變它的相關行為,
狀態模式詳情:Java設計模式之行為型:狀態模式
21、行為型-備忘錄模式:
備忘錄模式提供了一種恢復狀態的機制,在不破壞封裝的前提下,捕獲物件的某個時刻內部狀態,并保存在該物件之外,保證該物件能夠恢復到某個歷史狀態;備忘錄模式將保存的細節封裝在備忘錄中,除了創建它的創建者之外其他物件都不能訪問它,并且實作了即使要改變保存的細節也不影響客戶端,但是備忘錄模式都是多狀態和多備份的,會早用較多的記憶體,消耗資源,備忘錄模式的額UML結構圖如下:

備忘錄模式的核心就是備忘錄 Memento,在備忘錄中存盤的就是原發器 Originator 的部分或者所有的狀態資訊,而這些狀態資訊是不能夠被其他物件所訪問的,也就是說我們是不能使用備忘錄之外的物件來存盤這些狀態資訊,如果暴漏了內部狀態資訊就違反了封裝的原則,故備忘錄除了原發器外其他物件都不可以訪問,所以為了實作備忘錄模式的封裝,我們需要對備忘錄的訪問做些控制:
(1)對原發器:可以訪問備忘錄里的所有資訊,
(2)對負責人 caretaker:不可以訪問備忘錄里面的資料,但是他可以保存備忘錄并且可以將備忘錄傳遞給其他物件,
(3)其他物件:不可訪問也不可以保存,它只負責接收從負責人那里傳遞過來的備忘錄同時恢復原發器的狀態,
備忘錄模式詳情:Java設計模式之行為型:備忘錄模式
22、行為型-迭代器模式:
迭代器模式提供一種訪問集合中的各個元素,而不暴露其內部表示的方法,將在元素之間游走的職責交給迭代器,而不是集合物件,從而簡化集合容器的實作,讓集合容器專注于在它所應該專注的事情上,更加符合單一職責原則,避免在集合容器的抽象介面層中充斥著各種不同的遍歷操作,迭代器模式的UML結構圖如下:

迭代器模式詳情:Java設計模式之行為型:迭代器模式
23、行為型-解釋器模式:
解釋器模式,就是定義語言的文法,并建立一個解釋器來解釋該語言中的句子,通過構建解釋器,解決某一頻繁發生的特定型別問題實體,
解釋器模式描述了如何構成一個簡單的語言解釋器,主要應用在使用面向物件語言開發的編譯器中,它描述了如何為簡單的語言定義一個文法,如何在該語言中表示一個句子,以及如何解釋這些句子,
解釋器模式中除了能夠使用文法規則來定義一個語言,還能通過使用抽象語法樹來更加直觀表示、更好地地表示一個語言的構成,每一顆抽象語法樹對應一個語言實體,抽象語法樹描述了如何構成一個復雜的句子,通過對抽象語法樹的分析,可以識別出語言中的終結符和非終結符類, 在解釋器模式中由于每一種終結符運算式、非終結符運算式都會有一個具體的實體與之相對應,所以系統的擴展性比較好,
解釋器模式的UML如下:

解釋器模式詳情:Java設計模式之行為型:解釋器模式
相關推薦閱讀:
Spring常見面試題總結
SpringMVC常見面試題總結
Mybatis常見面試題總結
MySQL常見面試題總結
Redis常見面試題總結
RabbitMQ訊息佇列常見面試題總結
ElasticSearch搜索引擎常見面試題總結
計算機網路常見面試題總結
作業系統常見面試題總結
Java基礎、集合、多執行緒常見面試題總結
Java虛擬機常見面試題總結
Java常見設計模式總結
海量資料處理的方法總結
參考文章:
Java之美[從菜鳥到高手演變]之設計模式
Java之美[從菜鳥到高手演變]之設計模式二
Java之美[從菜鳥到高手演變]之設計模式三
Java之美[從菜鳥到高手演變]之設計模式四
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/301514.html
標籤:java
下一篇:??高級JAVA開發必備技能??java8 新日期時間API((五)JSR-310:實戰+原始碼分析),5萬字詳解(JAVA 小虛竹,建議收藏)
