溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java常見(jiàn)設(shè)計(jì)模式有哪些

發(fā)布時(shí)間:2022-03-08 09:38:56 來(lái)源:億速云 閱讀:88 作者:小新 欄目:編程語(yǔ)言

這篇文章主要介紹Java常見(jiàn)設(shè)計(jì)模式有哪些,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

一、設(shè)計(jì)模式總述:

1、什么是設(shè)計(jì)模式:

設(shè)計(jì)模式是一套經(jīng)過(guò)反復(fù)使用的代碼設(shè)計(jì)經(jīng)驗(yàn),目的是為了重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。 設(shè)計(jì)模式于己于人于系統(tǒng)都是多贏的,它使得代碼編寫(xiě)真正工程化,它是軟件工程的基石,如同大廈的一塊塊磚石一樣。項(xiàng)目中合理的運(yùn)用設(shè)計(jì)模式可以完美的解決很多問(wèn)題,每種模式在現(xiàn)實(shí)中都有相應(yīng)的原理來(lái)與之對(duì)應(yīng),每種模式描述了一個(gè)在我們周?chē)粩嘀貜?fù)發(fā)生的問(wèn)題,以及該問(wèn)題的核心解決方案,這也是它能被廣泛應(yīng)用的原因。總體來(lái)說(shuō),設(shè)計(jì)模式分為三大類:

  • 創(chuàng)建型模式:共5種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式

  • 結(jié)構(gòu)型模式:共7種:適配器模式、裝飾器模式、代理模式、橋接模式、外觀模式、組合模式、享元模式

  • 行為型模式:共11種:策略模式、模板方法模式、觀察者模式、責(zé)任鏈模式、訪問(wèn)者模式、中介者模式、迭代器模式、命令模式、狀態(tài)模式、備忘錄模式、解釋器模式

其實(shí)還有兩類:并發(fā)型模式和線程池模式,用一個(gè)圖片來(lái)整體描述一下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

2、設(shè)計(jì)模式的六大原則:

(1)開(kāi)閉原則 (Open Close Principle) :

開(kāi)閉原則指的是對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉。在對(duì)程序進(jìn)行擴(kuò)展的時(shí)候,不能去修改原有的代碼,想要達(dá)到這樣的效果,我們就需要使用接口或者抽象類

(2)依賴倒轉(zhuǎn)原則 (Dependence Inversion Principle):

依賴倒置原則是開(kāi)閉原則的基礎(chǔ),指的是針對(duì)接口編程,依賴于抽象而不依賴于具體

(3)里氏替換原則 (Liskov Substitution Principle) :

里氏替換原則是繼承與復(fù)用的基石,只有當(dāng)子類可以替換掉基類,且系統(tǒng)的功能不受影響時(shí),基類才能被復(fù)用,而子類也能夠在基礎(chǔ)類上增加新的行為。所以里氏替換原則指的是任何基類可以出現(xiàn)的地方,子類一定可以出現(xiàn)。

里氏替換原則是對(duì) “開(kāi)閉原則” 的補(bǔ)充,實(shí)現(xiàn) “開(kāi)閉原則” 的關(guān)鍵步驟就是抽象化,而基類與子類的繼承關(guān)系就是抽象化的具體實(shí)現(xiàn),所以里氏替換原則是對(duì)實(shí)現(xiàn)抽象化的具體步驟的規(guī)范。

(4)接口隔離原則 (Interface Segregation Principle):

使用多個(gè)隔離的接口,比使用單個(gè)接口要好,降低接口之間的耦合度與依賴,方便升級(jí)和維護(hù)方便

(5)迪米特原則 (Demeter Principle):

迪米特原則,也叫最少知道原則,指的是一個(gè)類應(yīng)當(dāng)盡量減少與其他實(shí)體進(jìn)行相互作用,使得系統(tǒng)功能模塊相對(duì)獨(dú)立,降低耦合關(guān)系。該原則的初衷是降低類的耦合,雖然可以避免與非直接的類通信,但是要通信,就必然會(huì)通過(guò)一個(gè)“中介”來(lái)發(fā)生關(guān)系,過(guò)分的使用迪米特原則,會(huì)產(chǎn)生大量的中介和傳遞類,導(dǎo)致系統(tǒng)復(fù)雜度變大,所以采用迪米特法則時(shí)要反復(fù)權(quán)衡,既要做到結(jié)構(gòu)清晰,又要高內(nèi)聚低耦合。

(6)合成復(fù)用原則 (Composite Reuse Principle):

盡量使用組合/聚合的方式,而不是使用繼承。

二、Java的23種設(shè)計(jì)模式:

接下來(lái)我們?cè)敿?xì)介紹Java中23種設(shè)計(jì)模式的概念,應(yīng)用場(chǎng)景等情況,并結(jié)合他們的特點(diǎn)及設(shè)計(jì)模式的原則進(jìn)行分析

1、創(chuàng)建型-工廠方法模式:

工廠方法模式分為三種:

(1)簡(jiǎn)單工廠模式:

建立一個(gè)工廠類,并定義一個(gè)接口對(duì)實(shí)現(xiàn)了同一接口的產(chǎn)品類進(jìn)行創(chuàng)建。首先看下關(guān)系圖:

Java常見(jiàn)設(shè)計(jì)模式有哪些

(2)工廠方法模式:

工廠方法模式是對(duì)簡(jiǎn)單工廠模式的改進(jìn),簡(jiǎn)單工廠的缺陷在于不符合“開(kāi)閉原則”,每次添加新產(chǎn)品類就需要修改工廠類,不利于系統(tǒng)的擴(kuò)展維護(hù)。而工廠方法將工廠抽象化,并定義一個(gè)創(chuàng)建對(duì)象的接口。每增加新產(chǎn)品,只需增加該產(chǎn)品以及對(duì)應(yīng)的具體實(shí)現(xiàn)工廠類,由具體工廠類決定要實(shí)例化的產(chǎn)品是哪個(gè),將對(duì)象的創(chuàng)建與實(shí)例化延遲到子類,這樣工廠的設(shè)計(jì)就符合“開(kāi)閉原則”了,擴(kuò)展時(shí)不必去修改原來(lái)的代碼。UML關(guān)系圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

(3)靜態(tài)工廠方法模式:

靜態(tài)工廠模式是將工廠方法模式里的方法置為靜態(tài)的,不需要?jiǎng)?chuàng)建實(shí)例,直接調(diào)用即可。

工廠方法模式詳情文章:Java設(shè)計(jì)模式之創(chuàng)建型:工廠模式詳解(簡(jiǎn)單工廠+工廠方法+抽象工廠)

2、創(chuàng)建型-抽象工廠模式:

抽象工廠模式主要用于創(chuàng)建相關(guān)對(duì)象的家族。當(dāng)一個(gè)產(chǎn)品族中需要被設(shè)計(jì)在一起工作時(shí),通過(guò)抽象工廠模式,能夠保證客戶端始終只使用同一個(gè)產(chǎn)品族中的對(duì)象;并且通過(guò)隔離具體類的生成,使得客戶端不需要明確指定具體生成類;所有的具體工廠都實(shí)現(xiàn)了抽象工廠中定義的公共接口,因此只需要改變具體工廠的實(shí)例,就可以在某種程度上改變整個(gè)軟件系統(tǒng)的行為。

但該模式的缺點(diǎn)在于添加新的行為時(shí)比較麻煩,如果需要添加一個(gè)新產(chǎn)品族對(duì)象時(shí),需要更改接口及其下所有子類,這必然會(huì)帶來(lái)很大的麻煩。

UML結(jié)構(gòu)圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

抽象工廠模式詳情:Java設(shè)計(jì)模式之創(chuàng)建型:工廠模式詳解(簡(jiǎn)單工廠+工廠方法+抽象工廠)

3、創(chuàng)建型-建造者模式:

建造者模式將復(fù)雜產(chǎn)品的創(chuàng)建步驟分解在在不同的方法中,使得創(chuàng)建過(guò)程更加清晰,從而更精確控制復(fù)雜對(duì)象的產(chǎn)生過(guò)程;通過(guò)隔離復(fù)雜對(duì)象的構(gòu)建與使用,也就是將產(chǎn)品的創(chuàng)建與產(chǎn)品本身分離開(kāi)來(lái),使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的對(duì)象;并且每個(gè)具體建造者都相互獨(dú)立,因此可以很方便地替換具體建造者或增加新的具體建造者,用戶使用不同的具體建造者即可得到不同的產(chǎn)品對(duì)象。UML結(jié)構(gòu)圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

建造者模式詳情:Java設(shè)計(jì)模式之創(chuàng)建型:建造者模式

4、創(chuàng)建型-單例模式:

單例模式可以確保系統(tǒng)中某個(gè)類只有一個(gè)實(shí)例,該類自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例的公共訪問(wèn)點(diǎn),除了該公共訪問(wèn)點(diǎn),不能通過(guò)其他途徑訪問(wèn)該實(shí)例。單例模式的優(yōu)點(diǎn)在于:

  • 系統(tǒng)中只存在一個(gè)共用的實(shí)例對(duì)象,無(wú)需頻繁創(chuàng)建和銷(xiāo)毀對(duì)象,節(jié)約了系統(tǒng)資源,提高系統(tǒng)的性能

  • 可以嚴(yán)格控制客戶怎么樣以及何時(shí)訪問(wèn)單例對(duì)象。

單例模式的寫(xiě)法有好幾種,主要有三種:懶漢式單例、餓漢式單例、登記式單例。

單例模式詳情:Java設(shè)計(jì)模式之創(chuàng)建型:?jiǎn)卫J?/p>

5、創(chuàng)建型-原型模式:

原型模式也是用于對(duì)象的創(chuàng)建,通過(guò)將一個(gè)對(duì)象作為原型,對(duì)其進(jìn)行復(fù)制克隆,產(chǎn)生一個(gè)與源對(duì)象類似的新對(duì)象。UML類圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

在 Java 中,原型模式的核心是就是原型類 Prototype,Prototype 類需要具備以下兩個(gè)條件:

  • 實(shí)現(xiàn) Cloneable 接口:

  • 重寫(xiě) Object 類中的 clone() 方法,用于返回對(duì)象的拷貝;

Object 類中的 clone() 方法默認(rèn)是淺拷貝,如果想要深拷貝對(duì)象,則需要在 clone() 方法中自定義自己的復(fù)制邏輯。

  • 淺復(fù)制:將一個(gè)對(duì)象復(fù)制后,基本數(shù)據(jù)類型的變量會(huì)重新創(chuàng)建,而引用類型指向的還是原對(duì)象所指向的內(nèi)存地址。

  • 深復(fù)制:將一個(gè)對(duì)象復(fù)制后,不論是基本數(shù)據(jù)類型還有引用類型,都是重新創(chuàng)建的。

使用原型模式進(jìn)行創(chuàng)建對(duì)象不僅簡(jiǎn)化對(duì)象的創(chuàng)建步驟,還比 new 方式創(chuàng)建對(duì)象的性能要好的多,因?yàn)?Object 類的 clone() 方法是一個(gè)本地方法,直接操作內(nèi)存中的二進(jìn)制流,特別是復(fù)制大對(duì)象時(shí),性能的差別非常明顯;

原型模式詳情:Java設(shè)計(jì)模式之創(chuàng)建型:原型模式

上面我們介紹了5種創(chuàng)建型模式,下面我們就開(kāi)始介紹下7種結(jié)構(gòu)型模式:適配器模式、裝飾模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。其中對(duì)象的適配器模式是各種模式的起源,如下圖:

Java常見(jiàn)設(shè)計(jì)模式有哪些

6、結(jié)構(gòu)型-適配器模式:

適配器模式主要用于將一個(gè)類或者接口轉(zhuǎn)化成客戶端希望的格式,使得原本不兼容的類可以在一起工作,將目標(biāo)類和適配者類解耦;同時(shí)也符合“開(kāi)閉原則”,可以在不修改原代碼的基礎(chǔ)上增加新的適配器類;將具體的實(shí)現(xiàn)封裝在適配者類中,對(duì)于客戶端類來(lái)說(shuō)是透明的,而且提高了適配者的復(fù)用性,但是缺點(diǎn)在于更換適配器的實(shí)現(xiàn)過(guò)程比較復(fù)雜。

所以,適配器模式比較適合以下場(chǎng)景:

  • (1)系統(tǒng)需要使用現(xiàn)有的類,而這些類的接口不符合系統(tǒng)的接口。

  • (2)使用第三方組件,組件接口定義和自己定義的不同,不希望修改自己的接口,但是要使用第三方組件接口的功能。

下面有個(gè)非常形象的例子很好地說(shuō)明了什么是適配器模式:

Java常見(jiàn)設(shè)計(jì)模式有哪些

適配器模式的主要實(shí)現(xiàn)有三種:類的適配器模式、對(duì)象的適配器模式、接口的適配器模式。三者的使用場(chǎng)景如下:

  • 類的適配器模式:當(dāng)希望將一個(gè)類轉(zhuǎn)換成滿足另一個(gè)新接口的類時(shí),可以使用類的適配器模式,創(chuàng)建一個(gè)新類,繼承原有的類,實(shí)現(xiàn)新的接口即可。

  • 對(duì)象的適配器模式:當(dāng)希望將一個(gè)對(duì)象轉(zhuǎn)換成滿足另一個(gè)新接口的對(duì)象時(shí),可以創(chuàng)建一個(gè)Wrapper類,持有原類的一個(gè)實(shí)例,在Wrapper類的方法中,調(diào)用實(shí)例的方法就行。

  • 接口的適配器模式:當(dāng)不希望實(shí)現(xiàn)一個(gè)接口中所有的方法時(shí),可以創(chuàng)建一個(gè)抽象類Wrapper,實(shí)現(xiàn)所有方法,我們寫(xiě)別的類的時(shí)候,繼承抽象類即可。

適配器模式詳情:Java設(shè)計(jì)模式之結(jié)構(gòu)型:適配器模式

7、結(jié)構(gòu)型-裝飾器模式:

裝飾器模式可以動(dòng)態(tài)給對(duì)象添加一些額外的職責(zé)從而實(shí)現(xiàn)功能的拓展,在運(yùn)行時(shí)選擇不同的裝飾器,從而實(shí)現(xiàn)不同的行為;比使用繼承更加靈活,通過(guò)對(duì)不同的裝飾類進(jìn)行排列組合,創(chuàng)造出很多不同行為,得到功能更為強(qiáng)大的對(duì)象;符合“開(kāi)閉原則”,被裝飾類與裝飾類獨(dú)立變化,用戶可以根據(jù)需要增加新的裝飾類和被裝飾類,在使用時(shí)再對(duì)其進(jìn)行組合,原有代碼無(wú)須改變。裝飾器模式的UML結(jié)構(gòu)圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

但是裝飾器模式也存在缺點(diǎn),首先會(huì)產(chǎn)生很多的小對(duì)象,增加了系統(tǒng)的復(fù)雜性,第二是排錯(cuò)比較困難,對(duì)于多次裝飾的對(duì)象,調(diào)試時(shí)尋找錯(cuò)誤可能需要逐級(jí)排查,較為煩瑣。

裝飾器模式詳情:Java設(shè)計(jì)模式之結(jié)構(gòu)型:裝飾器模式

8、結(jié)構(gòu)型-代理模式:

代理模式的設(shè)計(jì)動(dòng)機(jī)是通過(guò)代理對(duì)象來(lái)訪問(wèn)真實(shí)對(duì)象,通過(guò)建立一個(gè)對(duì)象代理類,由代理對(duì)象控制原對(duì)象的引用,從而實(shí)現(xiàn)對(duì)真實(shí)對(duì)象的操作。在代理模式中,代理對(duì)象主要起到一個(gè)中介的作用,用于協(xié)調(diào)與連接調(diào)用者(即客戶端)和被調(diào)用者(即目標(biāo)對(duì)象),在一定程度上降低了系統(tǒng)的耦合度,同時(shí)也保護(hù)了目標(biāo)對(duì)象。但缺點(diǎn)是在調(diào)用者與被調(diào)用者之間增加了代理對(duì)象,可能會(huì)造成請(qǐng)求的處理速度變慢。UML結(jié)構(gòu)圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

代理模式詳情:Java設(shè)計(jì)模式之結(jié)構(gòu)型:代理模式

9、結(jié)構(gòu)型-橋接模式:

橋接模式將系統(tǒng)的抽象部分與實(shí)現(xiàn)部分分離解耦,使他們可以獨(dú)立的變化。為了達(dá)到讓抽象部分和實(shí)現(xiàn)部分獨(dú)立變化的目的,橋接模式使用組合關(guān)系來(lái)代替繼承關(guān)系,抽象部分擁有實(shí)現(xiàn)部分的接口對(duì)象,從而能夠通過(guò)這個(gè)接口對(duì)象來(lái)調(diào)用具體實(shí)現(xiàn)部分的功能。也就是說(shuō),橋接模式中的橋接是一個(gè)單方向的關(guān)系,只能夠抽象部分去使用實(shí)現(xiàn)部分的對(duì)象,而不能反過(guò)來(lái)。

橋接模式符合“開(kāi)閉原則”,提高了系統(tǒng)的可拓展性,在兩個(gè)變化維度中任意擴(kuò)展一個(gè)維度,都不需要修改原來(lái)的系統(tǒng);并且實(shí)現(xiàn)細(xì)節(jié)對(duì)客戶不透明,可以隱藏實(shí)現(xiàn)細(xì)節(jié)。但是由于聚合關(guān)系建立在抽象層,要求開(kāi)發(fā)者針對(duì)抽象進(jìn)行編程,這增加系統(tǒng)的理解和設(shè)計(jì)難度。橋接模式的UML結(jié)構(gòu)圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

就像在Java中我們使用 JDBC 連接數(shù)據(jù)庫(kù)時(shí),在各個(gè)數(shù)據(jù)庫(kù)之間進(jìn)行切換,基本不需要?jiǎng)犹嗟拇a,原因就是使用了橋接模式,JDBC 提供統(tǒng)一接口,每個(gè)數(shù)據(jù)庫(kù)提供各自的實(shí)現(xiàn),然后由橋接類創(chuàng)建一個(gè)連接數(shù)據(jù)庫(kù)的驅(qū)動(dòng),使用某一個(gè)數(shù)據(jù)庫(kù)的時(shí)候只需要切換一下就行。JDBC 的結(jié)構(gòu)圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

在 JDBC 中,橋接模式的實(shí)現(xiàn)化角色 (Implementor) 為的 Driver 接口,具體實(shí)現(xiàn)化 (Concrete Implementor) 角色對(duì)應(yīng) MysqlDriver、OracleDriver 和 MariadbDriver,擴(kuò)展抽象化 (Refined Abstraction) 角色對(duì)應(yīng) DriverManager,不具有抽象化 (Abstraction) 角色作為擴(kuò)展抽象化角色的父類。

橋接模式詳情:Java設(shè)計(jì)模式之結(jié)構(gòu)型:橋接模式

10、結(jié)構(gòu)型-外觀模式:

外觀模式通過(guò)對(duì)客戶端提供一個(gè)統(tǒng)一的接口,用于訪問(wèn)子系統(tǒng)中的一群接口。使用外觀模式有以下幾點(diǎn)好處:

(1)更加易用:使得子系統(tǒng)更加易用,客戶端不再需要了解子系統(tǒng)內(nèi)部的實(shí)現(xiàn),也不需要跟眾多子系統(tǒng)內(nèi)部的模塊進(jìn)行交互,只需要跟外觀類交互就可以了;

(2)松散耦合:將客戶端與子系統(tǒng)解耦,讓子系統(tǒng)內(nèi)部的模塊能更容易擴(kuò)展和維護(hù)。

(3)更好的劃分訪問(wèn)層次:通過(guò)合理使用 Facade,可以更好地劃分訪問(wèn)的層次,有些方法是對(duì)系統(tǒng)外的,有些方法是系統(tǒng)內(nèi)部使用的。把需要暴露給外部的功能集中到門(mén)面中,這樣既方便客戶端使用,也很好地隱藏了內(nèi)部的細(xì)節(jié)。

但是如果外觀模式對(duì)子系統(tǒng)類做太多的限制則減少了可變性和靈活性,所以外觀模式適用于為復(fù)雜子系統(tǒng)提供一個(gè)簡(jiǎn)單接口,提高系統(tǒng)的易用性場(chǎng)景 以及 引入外觀模式將子系統(tǒng)與客戶端進(jìn)行解耦,提高子系統(tǒng)的獨(dú)立性和可移植性。

外觀模式的UML結(jié)構(gòu)圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

外觀模式詳情: Java設(shè)計(jì)模式之結(jié)構(gòu)型:外觀模式

11、結(jié)構(gòu)型-組合模式:

組合模式將葉子對(duì)象和容器對(duì)象進(jìn)行遞歸組合,形成樹(shù)形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu),使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性,能夠像處理葉子對(duì)象一樣來(lái)處理組合對(duì)象,無(wú)需進(jìn)行區(qū)分,從而使用戶程序能夠與復(fù)雜元素的內(nèi)部結(jié)構(gòu)進(jìn)行解耦。

組合模式最關(guān)鍵的地方是葉子對(duì)象和組合對(duì)象實(shí)現(xiàn)了相同的抽象構(gòu)建類,它既可表示葉子對(duì)象,也可表示容器對(duì)象,客戶僅僅需要針對(duì)這個(gè)抽象構(gòu)建類進(jìn)行編程,這就是組合模式能夠?qū)⑷~子節(jié)點(diǎn)和對(duì)象節(jié)點(diǎn)進(jìn)行一致處理的原因。組合模式的UML結(jié)構(gòu)圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

組合模式詳情: Java設(shè)計(jì)模式之結(jié)構(gòu)型:組合模式

12、結(jié)構(gòu)型-享元模式:

享元模式通過(guò)共享技術(shù)有效地支持細(xì)粒度、狀態(tài)變化小的對(duì)象復(fù)用,當(dāng)系統(tǒng)中存在有多個(gè)相同的對(duì)象,那么只共享一份,不必每個(gè)都去實(shí)例化一個(gè)對(duì)象,極大地減少系統(tǒng)中對(duì)象的數(shù)量,從而節(jié)省資源。

享元模式的核心是享元工廠類,享元工廠類維護(hù)了一個(gè)對(duì)象存儲(chǔ)池,當(dāng)客戶端需要對(duì)象時(shí),首先從享元池中獲取,如果享元池中存在對(duì)象實(shí)例則直接返回,如果享元池中不存在,則創(chuàng)建一個(gè)新的享元對(duì)象實(shí)例返回給用戶,并在享元池中保存該新增對(duì)象,這點(diǎn)有些單例的意思。

工廠類通常會(huì)使用集合類型來(lái)保存對(duì)象,如 HashMap、Hashtable、Vector 等等,在 Java 中,數(shù)據(jù)庫(kù)連接池、線程池等都是用享元模式的應(yīng)用。

享元模式的UML結(jié)構(gòu)圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

Java 中,String 類型就是使用享元模式,String 對(duì)象是 final 類型,對(duì)象一旦創(chuàng)建就不可改變。而 Java 的字符串常量都是存在字符串常量池中的,JVM 會(huì)確保一個(gè)字符串常量在常量池中只有一個(gè)拷貝。

而且提到共享池,我們也很容易聯(lián)想到 Java 里面的JDBC連接池,通過(guò)連接池的管理,實(shí)現(xiàn)了數(shù)據(jù)庫(kù)連接的共享,不需要每一次都重新創(chuàng)建連接,節(jié)省了數(shù)據(jù)庫(kù)重新創(chuàng)建的開(kāi)銷(xiāo),提升了系統(tǒng)的性能!

享元模式詳情:Java設(shè)計(jì)模式之結(jié)構(gòu)型:享元模式

前面我們介紹了7種結(jié)構(gòu)型設(shè)計(jì)模式,接下來(lái)我們介紹一下11種行為型設(shè)計(jì)模式:策略模式、模板方法模式、觀察者模式、迭代子模式、責(zé)任鏈模式、命令模式、備忘錄模式、狀態(tài)模式、訪問(wèn)者模式、中介者模式、解釋器模式。先來(lái)張圖,看看這11中模式的關(guān)系:

Java常見(jiàn)設(shè)計(jì)模式有哪些

13、行為型-策略模式:

將類中經(jīng)常改變或者可能改變的部分提取為作為一個(gè)抽象策略接口類,然后在類中包含這個(gè)對(duì)象的實(shí)例,這樣類實(shí)例在運(yùn)行時(shí)就可以隨意調(diào)用實(shí)現(xiàn)了這個(gè)接口的類的行為。

比如定義一系列的算法,把每一個(gè)算法封裝起來(lái),并且使它們可相互替換,使得算法可獨(dú)立于使用它的客戶而變化,這就是策略模式。UML結(jié)構(gòu)圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

策略模式的優(yōu)點(diǎn)在于可以動(dòng)態(tài)改變對(duì)象的行為;但缺點(diǎn)是會(huì)產(chǎn)生很多策略類,并且策略模式的決定權(quán)在用戶,系統(tǒng)只是提供不同算法的實(shí)現(xiàn),所以客戶端必須知道所有的策略類,并自行決定使用哪一個(gè)策略類;

策略模式適用用于以下幾種場(chǎng)景:

  • (1)應(yīng)用程序需要實(shí)現(xiàn)特定的功能服務(wù),而該程序有多種實(shí)現(xiàn)方式使用,所以需要?jiǎng)討B(tài)地在幾種算法中選擇一種

  • (2)一個(gè)類定義了多種行為算法,并且這些行為在類的操作中以多個(gè)條件語(yǔ)句的形式出現(xiàn),就可以將相關(guān)的條件分支移入它們各自的Strategy類中以代替這些條件語(yǔ)句。

策略模式詳情:Java設(shè)計(jì)模式之行為型:策略模式

14、行為型-模板方法:

模板方法是基于繼承實(shí)現(xiàn)的,在抽象父類中聲明一個(gè)模板方法,并在模板方法中定義算法的執(zhí)行步驟(即算法骨架)。在模板方法模式中,可以將子類共性的部分放在父類中實(shí)現(xiàn),而特性的部分延遲到子類中實(shí)現(xiàn),只需將特性部分在父類中聲明成抽象方法即可,使得子類可以在不改變算法結(jié)構(gòu)的情況下,重新定義算法中的某些步驟,不同的子類可以以不同的方式來(lái)實(shí)現(xiàn)這些邏輯。

模板方法模式的優(yōu)點(diǎn)在于符合“開(kāi)閉原則”,也能夠?qū)崿F(xiàn)代碼復(fù)用,將不變的行為轉(zhuǎn)移到父類,去除子類中的重復(fù)代碼。但是缺點(diǎn)是不同的實(shí)現(xiàn)都需要定義一個(gè)子類,導(dǎo)致類的個(gè)數(shù)的增加使得系統(tǒng)更加龐大,設(shè)計(jì)更加抽象。模板方法模式的UML圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

模板方法詳情:Java設(shè)計(jì)模式之行為型:模板方法模式

15、行為型-責(zé)任鏈模式:

職責(zé)鏈可以將請(qǐng)求的處理者組織成一條鏈,并將請(qǐng)求沿著鏈傳遞,如果某個(gè)處理者能夠處理請(qǐng)求則處理,否則將該請(qǐng)求交由上級(jí)處理??蛻舳酥恍鑼⒄?qǐng)求發(fā)送到職責(zé)鏈上,無(wú)須關(guān)注請(qǐng)求的處理細(xì)節(jié),通過(guò)職責(zé)鏈將請(qǐng)求的發(fā)送者和處理者解耦了,這也是職責(zé)鏈的設(shè)計(jì)動(dòng)機(jī)。

職責(zé)鏈模式可以簡(jiǎn)化對(duì)象間的相互連接,因?yàn)榭蛻舳撕吞幚碚叨紱](méi)有對(duì)方明確的信息,同時(shí)處理者也不知道職責(zé)鏈中的結(jié)構(gòu),處理者只需保存一個(gè)指向后續(xù)者的引用,而不需要保存所有候選者的引用。

另外職責(zé)鏈模式增加了系統(tǒng)的靈活性,我們可以任意增加或更改處理者,甚至更改處理者的順序,不過(guò)有可能會(huì)導(dǎo)致一個(gè)請(qǐng)求無(wú)論如何也得不到處理,因?yàn)樗赡鼙环胖迷阪溎┒恕?/p>

所以責(zé)任鏈模式有以下幾個(gè)優(yōu)點(diǎn):

  • (1)降低耦合度,將請(qǐng)求的發(fā)送者和接收者解耦。反映在代碼上就是不需要在類中寫(xiě)很多丑陋的 if….else 語(yǔ)句,如果用了職責(zé)鏈,相當(dāng)于我們面對(duì)一個(gè)黑箱,只需將請(qǐng)求遞交給其中一個(gè)處理者,然后讓黑箱內(nèi)部去負(fù)責(zé)傳遞就可以了。

  • (2)簡(jiǎn)化了對(duì)象,使得對(duì)象不需要鏈的結(jié)構(gòu)。

  • (3)增加系統(tǒng)的靈活性,通過(guò)改變鏈內(nèi)的成員或者調(diào)動(dòng)他們的次序,允許動(dòng)態(tài)地新增或者刪除處理者

  • (4)增加新的請(qǐng)求處理類很方便。

但是責(zé)任鏈模式也存在一些缺點(diǎn):

  • (1)不能保證請(qǐng)求一定被成功處理

  • (2)系統(tǒng)性能將受到一定影響,并且可能會(huì)造成循環(huán)調(diào)用。

  • (3)可能不容易觀察運(yùn)行時(shí)的特征,而且在進(jìn)行代碼調(diào)試時(shí)不太方便,有礙于除錯(cuò)。

責(zé)任鏈模式的UML結(jié)構(gòu)圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

責(zé)任鏈模式詳情:Java設(shè)計(jì)模式之行為型:責(zé)任鏈模式

16、行為型-觀察者模式:

觀察者模式又稱為 發(fā)布-訂閱模式,定義了對(duì)象之間一對(duì)多依賴關(guān)系,當(dāng)目標(biāo)對(duì)象(被觀察者)的狀態(tài)發(fā)生改變時(shí),它的所有依賴者(觀察者)都會(huì)收到通知。一個(gè)觀察目標(biāo)可以對(duì)應(yīng)多個(gè)觀察者,而這些觀察者之間沒(méi)有相互聯(lián)系,所以能夠根據(jù)需要增加和刪除觀察者,使得系統(tǒng)更易于擴(kuò)展,符合開(kāi)閉原則;并且觀察者模式讓目標(biāo)對(duì)象和觀察者松耦合,雖然彼此不清楚對(duì)方的細(xì)節(jié),但依然可以交互,目標(biāo)對(duì)象只知道一個(gè)具體的觀察者列表,但并不認(rèn)識(shí)任何一個(gè)具體的觀察者,它只知道他們都有一個(gè)共同的接口。

但觀察者模式的缺點(diǎn)在于如果存在很多個(gè)被觀察者的話,那么將需要花費(fèi)一定時(shí)間通知所有的觀察者,如果觀察者與被觀察者之間存在循環(huán)依賴的話,那么可能導(dǎo)致系統(tǒng)崩潰,并且觀察者模式?jīng)]有相應(yīng)的機(jī)制讓觀察者知道被觀察對(duì)象是怎么發(fā)生變化的,而僅僅只是知道觀察目標(biāo)發(fā)生了變化。觀察者模式的UML結(jié)構(gòu)圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

觀察者模式詳情:Java設(shè)計(jì)模式之行為型:觀察者模式

17、行為型-訪問(wèn)者模式:

訪問(wèn)者模式就是一種分離對(duì)象數(shù)據(jù)結(jié)構(gòu)與行為 (基于數(shù)據(jù)結(jié)構(gòu)的操作) 的方法,通過(guò)這種分離,達(dá)到為一個(gè)被訪問(wèn)者動(dòng)態(tài)添加新的操作而無(wú)需做其它修改的效果,使得添加作用于這些數(shù)據(jù)結(jié)構(gòu)的新操作變得簡(jiǎn)單,并且不需要改變各數(shù)據(jù)結(jié)構(gòu),為不同類型的數(shù)據(jù)結(jié)構(gòu)提供多種訪問(wèn)操作方式,這樣是訪問(wèn)者模式的設(shè)計(jì)動(dòng)機(jī)。

除了使新增訪問(wèn)操作變得更加簡(jiǎn)單,也能夠在不修改現(xiàn)有類的層次結(jié)構(gòu)下,定義該類層次結(jié)構(gòu)的操作,并將有關(guān)元素對(duì)象的訪問(wèn)行為集中到一個(gè)訪問(wèn)者對(duì)象中,而不是分散搞一個(gè)個(gè)的元素類中。

但訪問(wèn)者模式的缺點(diǎn)在于讓增加新的元素類變得困難,每增加一個(gè)新的元素類都意味著要在抽象訪問(wèn)者角色中增加一個(gè)新的抽象操作,并在每一個(gè)具體訪問(wèn)者類中增加相應(yīng)的具體操作,違背了“開(kāi)閉原則”的要求;

所以訪問(wèn)者模式適用于對(duì)象結(jié)構(gòu)中很少改變,但經(jīng)常需要在此對(duì)象結(jié)構(gòu)上定義新的操作的系統(tǒng),使得算法操作的增加變得簡(jiǎn)單;或者需要對(duì)一個(gè)對(duì)象結(jié)構(gòu)中進(jìn)行很多不同并且不相關(guān)的操作,并且需要避免讓這些操作污染這些對(duì)象,也不希望在增加新操作時(shí)修改這些類的場(chǎng)景。

訪問(wèn)者模式的UML結(jié)構(gòu)圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

從上面的 UML 結(jié)構(gòu)圖中我們可以看出,訪問(wèn)者模式主要分為兩個(gè)層次結(jié)構(gòu),一個(gè)是訪問(wèn)者層次結(jié)構(gòu),提供了抽象訪問(wèn)者和具體訪問(wèn)者,主要用于聲明一些操作;一個(gè)是元素層次結(jié)構(gòu),提供了抽象元素和具體元素,主要用于聲明 accept 操作;而對(duì)象結(jié)構(gòu) ObjectStructure 作為兩者的橋梁,存儲(chǔ)了不同類型的對(duì)象,以便不同的訪問(wèn)者來(lái)訪問(wèn),相同訪問(wèn)者可以以不同的方式訪問(wèn)不同的元素,所以在訪問(wèn)者模式中增加新的訪問(wèn)者無(wú)需修改現(xiàn)有代碼,可擴(kuò)展行強(qiáng)。

在訪問(wèn)者模式使用了雙分派技術(shù),所謂雙分派技術(shù)就是在選擇方法的時(shí)候,不僅僅要根據(jù)消息接收者的運(yùn)行時(shí)區(qū)別,還要根據(jù)參數(shù)的運(yùn)行時(shí)區(qū)別。在訪問(wèn)者模式中,客戶端將具體狀態(tài)當(dāng)做參數(shù)傳遞給具體訪問(wèn)者,這里完成第一次分派,然后具體訪問(wèn)者作為參數(shù)的“具體狀態(tài)”中的方法,同時(shí)也將自己this作為參數(shù)傳遞進(jìn)去,這里就完成了第二次分派。雙分派意味著得到的執(zhí)行操作決定于請(qǐng)求的種類和接受者的類型。

訪問(wèn)者模式詳情:Java設(shè)計(jì)模式之行為型:訪問(wèn)者模式

18、行為型-中介者模式:

Java常見(jiàn)設(shè)計(jì)模式有哪些         中介者模式通過(guò)中介者對(duì)象來(lái)封裝一系列的對(duì)象交互,將對(duì)象間復(fù)雜的關(guān)系網(wǎng)狀結(jié)構(gòu)變成結(jié)構(gòu)簡(jiǎn)單的以中介者為核心的星形結(jié)構(gòu),對(duì)象間一對(duì)多的關(guān)聯(lián)轉(zhuǎn)變?yōu)橐粚?duì)一的關(guān)聯(lián),簡(jiǎn)化對(duì)象間的關(guān)系,便于理解;各個(gè)對(duì)象之間的關(guān)系被解耦,每個(gè)對(duì)象不再和它關(guān)聯(lián)的對(duì)象直接發(fā)生相互作用,而是通過(guò)中介者對(duì)象來(lái)與關(guān)聯(lián)的對(duì)象進(jìn)行通訊,使得對(duì)象可以相對(duì)獨(dú)立地使用,提高了對(duì)象的可復(fù)用和系統(tǒng)的可擴(kuò)展性。

在中介者模式中,中介者類處于核心地位,它封裝了系統(tǒng)中所有對(duì)象類之間的關(guān)系,除了簡(jiǎn)化對(duì)象間的關(guān)系,還可以對(duì)對(duì)象間的交互進(jìn)行進(jìn)一步的控制。中介者模式的UML結(jié)構(gòu)圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

但是,中介者對(duì)象封裝了對(duì)象之間的關(guān)聯(lián)關(guān)系,導(dǎo)致中介者對(duì)象變得比較龐大復(fù)雜,所承擔(dān)的責(zé)任也比較多,維護(hù)起來(lái)也比較困難,它需要知道每個(gè)對(duì)象和他們之間的交互細(xì)節(jié),如果它出問(wèn)題,將會(huì)導(dǎo)致整個(gè)系統(tǒng)都會(huì)出問(wèn)題。

中介者模式詳情:Java設(shè)計(jì)模式之行為型:中介者模式

19、行為型-命令模式:

命令模式的本質(zhì)是將請(qǐng)求封裝成對(duì)象,將發(fā)出命令與執(zhí)行命令的責(zé)任分開(kāi),命令的發(fā)送者和接收者完全解耦,發(fā)送者只需知道如何發(fā)送命令,不需要關(guān)心命令是如何實(shí)現(xiàn)的,甚至是否執(zhí)行成功都不需要理會(huì)。命令模式的關(guān)鍵在于引入了抽象命令接口,發(fā)送者針對(duì)抽象命令接口編程,只有實(shí)現(xiàn)了抽象命令接口的具體命令才能與接收者相關(guān)聯(lián)。

使用命令模式的優(yōu)勢(shì)在于降低了系統(tǒng)的耦合度,而且新命令可以很方便添加到系統(tǒng)中,也容易設(shè)計(jì)一個(gè)組合命令。但缺點(diǎn)在于會(huì)導(dǎo)致某些系統(tǒng)有過(guò)多的具體命令類,因?yàn)獒槍?duì)每一個(gè)命令都需要設(shè)計(jì)一個(gè)具體命令類。

命令模式的UML結(jié)構(gòu)圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

命令模式詳情: Java設(shè)計(jì)模式之行為型:命令模式

20、行為型-狀態(tài)模式:

狀態(tài)模式,就是允許對(duì)象在內(nèi)部狀態(tài)發(fā)生改變時(shí)改變它的行為,對(duì)象看起來(lái)就好像修改了它的類,也就是說(shuō)以狀態(tài)為原子來(lái)改變它的行為,而不是通過(guò)行為來(lái)改變狀態(tài)。

當(dāng)對(duì)象的行為取決于它的屬性時(shí),我們稱這些屬性為狀態(tài),那該對(duì)象就稱為狀態(tài)對(duì)象。對(duì)于狀態(tài)對(duì)象而言,它的行為依賴于它的狀態(tài),比如要預(yù)訂房間,只有當(dāng)該房間空閑時(shí)才能預(yù)訂,想入住該房間也只有當(dāng)你預(yù)訂了該房間或者該房間為空閑時(shí)。對(duì)于這樣的一個(gè)對(duì)象,當(dāng)它的外部事件產(chǎn)生互動(dòng)的時(shí)候,其內(nèi)部狀態(tài)就會(huì)發(fā)生變化,從而使得他的行為也隨之發(fā)生變化。

狀態(tài)模式的UML結(jié)構(gòu)圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

從上面的UML結(jié)構(gòu)圖我們可以看出狀態(tài)模式的優(yōu)點(diǎn)在于:

(1)封裝了轉(zhuǎn)換規(guī)則,允許狀態(tài)轉(zhuǎn)換邏輯與狀態(tài)對(duì)象合成一體,而不是某一個(gè)巨大的條件語(yǔ)句塊

(2)將所有與狀態(tài)有關(guān)的行為放到一個(gè)類中,可以方便地增加新的狀態(tài),只需要改變對(duì)象狀態(tài)即可改變對(duì)象的行為。

但是狀態(tài)模式的缺點(diǎn)在于:

(1)需要在枚舉狀態(tài)之前需要確定狀態(tài)種類

(2)會(huì)導(dǎo)致增加系統(tǒng)類和對(duì)象的個(gè)數(shù)。

(3)對(duì) “開(kāi)閉原則” 的支持并不友好,新增狀態(tài)類需要修改那些負(fù)責(zé)狀態(tài)轉(zhuǎn)換的源代碼,否則無(wú)法切換到新增狀態(tài);而且修改某個(gè)狀態(tài)類的行為也需修改對(duì)應(yīng)類的源代碼。

所以狀態(tài)模式適用于:代碼中包含大量與對(duì)象狀態(tài)有關(guān)的條件語(yǔ)句,以及對(duì)象的行為依賴于它的狀態(tài),并且可以根據(jù)它的狀態(tài)改變而改變它的相關(guān)行為。

狀態(tài)模式詳情:Java設(shè)計(jì)模式之行為型:狀態(tài)模式

21、行為型-備忘錄模式:

備忘錄模式提供了一種恢復(fù)狀態(tài)的機(jī)制,在不破壞封裝的前提下,捕獲對(duì)象的某個(gè)時(shí)刻內(nèi)部狀態(tài),并保存在該對(duì)象之外,保證該對(duì)象能夠恢復(fù)到某個(gè)歷史狀態(tài);備忘錄模式將保存的細(xì)節(jié)封裝在備忘錄中,除了創(chuàng)建它的創(chuàng)建者之外其他對(duì)象都不能訪問(wèn)它,并且實(shí)現(xiàn)了即使要改變保存的細(xì)節(jié)也不影響客戶端。但是備忘錄模式都是多狀態(tài)和多備份的,會(huì)早用較多的內(nèi)存,消耗資源。備忘錄模式的額UML結(jié)構(gòu)圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

備忘錄模式的核心就是備忘錄 Memento,在備忘錄中存儲(chǔ)的就是原發(fā)器 Originator 的部分或者所有的狀態(tài)信息,而這些狀態(tài)信息是不能夠被其他對(duì)象所訪問(wèn)的,也就是說(shuō)我們是不能使用備忘錄之外的對(duì)象來(lái)存儲(chǔ)這些狀態(tài)信息,如果暴漏了內(nèi)部狀態(tài)信息就違反了封裝的原則,故備忘錄除了原發(fā)器外其他對(duì)象都不可以訪問(wèn)。所以為了實(shí)現(xiàn)備忘錄模式的封裝,我們需要對(duì)備忘錄的訪問(wèn)做些控制:

(1)對(duì)原發(fā)器:可以訪問(wèn)備忘錄里的所有信息。

(2)對(duì)負(fù)責(zé)人 caretaker:不可以訪問(wèn)備忘錄里面的數(shù)據(jù),但是他可以保存?zhèn)渫洸⑶铱梢詫渫泜鬟f給其他對(duì)象。

(3)其他對(duì)象:不可訪問(wèn)也不可以保存,它只負(fù)責(zé)接收從負(fù)責(zé)人那里傳遞過(guò)來(lái)的備忘錄同時(shí)恢復(fù)原發(fā)器的狀態(tài)。

備忘錄模式詳情:Java設(shè)計(jì)模式之行為型:備忘錄模式

22、行為型-迭代器模式:

迭代器模式提供一種訪問(wèn)集合中的各個(gè)元素,而不暴露其內(nèi)部表示的方法。將在元素之間游走的職責(zé)交給迭代器,而不是集合對(duì)象,從而簡(jiǎn)化集合容器的實(shí)現(xiàn),讓集合容器專注于在它所應(yīng)該專注的事情上,更加符合單一職責(zé)原則,避免在集合容器的抽象接口層中充斥著各種不同的遍歷操作。迭代器模式的UML結(jié)構(gòu)圖如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

迭代器模式詳情:Java設(shè)計(jì)模式之行為型:迭代器模式

23、行為型-解釋器模式:

解釋器模式,就是定義語(yǔ)言的文法,并建立一個(gè)解釋器來(lái)解釋該語(yǔ)言中的句子,通過(guò)構(gòu)建解釋器,解決某一頻繁發(fā)生的特定類型問(wèn)題實(shí)例。

解釋器模式描述了如何構(gòu)成一個(gè)簡(jiǎn)單的語(yǔ)言解釋器,主要應(yīng)用在使用面向?qū)ο笳Z(yǔ)言開(kāi)發(fā)的編譯器中,它描述了如何為簡(jiǎn)單的語(yǔ)言定義一個(gè)文法,如何在該語(yǔ)言中表示一個(gè)句子,以及如何解釋這些句子。

解釋器模式中除了能夠使用文法規(guī)則來(lái)定義一個(gè)語(yǔ)言,還能通過(guò)使用抽象語(yǔ)法樹(shù)來(lái)更加直觀表示、更好地地表示一個(gè)語(yǔ)言的構(gòu)成,每一顆抽象語(yǔ)法樹(shù)對(duì)應(yīng)一個(gè)語(yǔ)言實(shí)例。抽象語(yǔ)法樹(shù)描述了如何構(gòu)成一個(gè)復(fù)雜的句子,通過(guò)對(duì)抽象語(yǔ)法樹(shù)的分析,可以識(shí)別出語(yǔ)言中的終結(jié)符和非終結(jié)符類。 在解釋器模式中由于每一種終結(jié)符表達(dá)式、非終結(jié)符表達(dá)式都會(huì)有一個(gè)具體的實(shí)例與之相對(duì)應(yīng),所以系統(tǒng)的擴(kuò)展性比較好。

解釋器模式的UML如下:

Java常見(jiàn)設(shè)計(jì)模式有哪些

解釋器模式詳情:Java設(shè)計(jì)模式之行為型:解釋器模式


以上是“Java常見(jiàn)設(shè)計(jì)模式有哪些”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI