首頁 > Java > java教程 > 主體

詳細介紹23種Java常見設計模式

WBOY
發布: 2022-03-07 17:33:33
轉載
2880 人瀏覽過

本篇文章為大家帶來了關於java中的相關知識,其中主要介紹了幾種常見的設計模式,設計模式是一套經過反覆使用的程式碼設計經驗,目的是為了重複使用程式碼、讓程式碼更容易被他人理解、保證程式碼可靠性,希望對大家有幫助。

詳細介紹23種Java常見設計模式

推薦學習:《java教學

# 一、設計模式總述:

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) 角色對應OracleDriver 和MariadbDriver,擴充抽象(Refined Abstraction) 角色對應DriverManager,不具有抽象化(Abstraction) 角色作為擴展抽象化角色的父類別。

橋接模式詳情:Java設計模式之結構型:橋接模式

10、結構型-外觀模式:

        外觀模式透過對顧客端提供一個統一的接口,用於存取子系統中的一群接口。使用外觀模式有以下幾點好處:

(1)更加易用:使得子系統更加易用,客戶端不再需要了解子系統內部的實現,也不需要跟眾多子系統內部的模組進行交互,只需要跟外觀類別交互就可以了;

(2)鬆散耦合:將客戶端與子系統解耦,讓子系統內部的模組能更容易擴展和維護。

(3)更好的劃分存取層次:透過合理使用 Facade,可以更好地劃分存取的層次,有些方法是對系統外的,有些方法是系統內部使用的。把需要暴露給外部的功能集中到門面中,這樣既方便客戶端使用,也很好地隱藏了內部的細節。

        但是如果外觀模式對子系統類別做太多的限制則減少了可變性和靈活性,所以外觀模式適用於為複雜子系統提供一個簡單接口,提高系統的易用性場景以及引入外觀模式將子系統與客戶端解耦,提高子系統的獨立性和可移植性。

        外觀模式的UML結構圖如下:

外觀模式詳情: Java設計模式之結構型:外觀模式

11、結構型-組合模式:

        組合模式將葉子物件和容器物件進行遞歸組合,形成樹形結構以表示「部分-整體」的層次結構,使得使用者對單一對象和組合對象的使用具有一致性,能夠像處理葉子對像一樣來處理組合對象,無需進行區分,從而使用戶程式能夠與複雜元素的內部結構進行解耦。

        組合模式最關鍵的地方是葉子對象和組合對象實現了相同的抽象構建類,它既可表示葉子對象,也可表示容器對象,客戶僅需要針對這個抽象構建類進行編程,這就是為什麼組合模式能夠將葉子節點和物件節點進行一致處理的原因。組合模式的UML結構圖如下:

組合模式詳情: Java設計模式之結構型:組合模式

12、結構型-享幣模式:

        享元模式透過共享技術有效地支援細粒度、狀態變化小的對象重複使用,當系統中存在有多個相同的對象,那麼隻共享一份,不必每個都去實例化一個對象,大大減少系統中對象的數量,從而節省資源。

        享元模式的核心是享元工廠類,享元工廠類維護了一個物件儲存池,當客戶端需要物件時,首先從享元池中獲取,如果享元池中存在對象實例則直接傳回,如果享元池中不存在,則創建一個新的享元對象實例返回給用戶,並在享元池中保存該新增對象,這點有些單例的意思。

        工廠類別通常使用集合型別來保存對象,如 HashMap、Hashtable、Vector 等等,在 Java 中,資料庫連線池、執行緒池等都是使用享元模式的應用。

        享元模式的UML結構圖如下:

         JavaJava中,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設計模式之行為型:解譯器模式

#推薦學習:《java學習教學

以上是詳細介紹23種Java常見設計模式的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:csdn.net
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!