創(chuàng)建模式
單例模式
什么是設(shè)計模式

- 設(shè)計模式:一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類編目的、代碼設(shè)計經(jīng)驗的總結(jié)。
- 目的:可重用代碼,讓代碼更容易被他人理解、保證代碼可靠性。
- Java中的設(shè)計模式:23種:
- [x] 創(chuàng)建型模式:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式;
- [x] 結(jié)構(gòu)型模式:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式;
- [x] 行為型模式:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態(tài)模式、訪問者模式、中介者模式、解釋器模式;
- [x] 其它模式:并發(fā)型模式和線程池模式。
單例模式:保證整個應(yīng)用中某個實例有且只有一個。
舉例:配置文件、工具類、線程池、緩存、日志對象等
單利模式實現(xiàn)
- 應(yīng)用場合: 有些對象只需要一個就足夠了.
- 作用: 保證整個應(yīng)用程序中某個實例有且只有一個.
(1) 餓漢式
懶漢模式,先只是進行聲明,當存在該實例的時候直接返回,不存在的時候再去新建
/*
* 單例模式Singleton
* 應(yīng)用場合:有些對象只需要一個就足夠了,如古代皇帝、老婆
* 作用:保證整個應(yīng)用程序中某個實例有且只有一個
* 類型:餓漢模式、懶漢模式
*/
public class Singleton {
//1.將構(gòu)造方法私有化,不允許外部直接創(chuàng)建對象
private Singleton(){
}
//2.創(chuàng)建類的唯一實例,使用private static修飾
private static Singleton instance=new Singleton();
//3.提供一個用于獲取實例的方法,使用public static修飾
public static Singleton getInstance(){
return instance;
}
}
(2) 懶漢式
餓漢模式特點之一就是在類加載是這個類的實例就被加載了,無論之后是否用到這個實例
/*
* 懶漢模式
*/
public class Singleton2 {
//1.將構(gòu)造方法私有化,不允許外邊直接創(chuàng)建對象
private Singleton2(){
}
//2.聲明類的唯一實例,使用private static修飾
private static Singleton2 instance;
//3.提供一個用于獲取實例的方法,使用public static修飾
public static Singleton2 getInstance(){
if(instance == null){
instance = new Singleton2();
}
return instance;
}
}
餓漢式、懶漢式區(qū)別
餓漢模式:在加載類的時候就加載了實例,因此加載慢,但運行快,線程安全
懶漢模式:在加載類時沒有加載實例,加載快,運行時加載實例,運行慢,線程不安全
工廠模式
工廠模式的概念、意圖、應(yīng)用場景、動機
-
工廠模式的概念
-
工廠模式的意圖
-
工廠模式的應(yīng)用場景
-
工廠模式的動機
-
工廠模式類圖
-
抽象工廠模式類圖
工廠模式的應(yīng)用
-
常見的應(yīng)用
(1) JDBC的工作流程
(2) spring beanfactory

-
對比:
-
實現(xiàn)了
-
適用場景
結(jié)構(gòu)型模式
代理模式
1. 概念
- [x] 為其他對象提供一種代理,以控制對這個對象的訪問(例如火車站代售處)。代理對象起到中介作用,可去掉功能服務(wù)或增加額外的服務(wù)。
2. 代理模式的分類:
- [ ] 遠程代理模式: 為不同地理的對象提供局域網(wǎng)代表對象(例子:通過遠程代理可以監(jiān)控各個店鋪,使之可以直觀的了解店里的情況)
- [ ] 虛擬代理: 根據(jù)需要將資源消耗很大的對象進行延遲,真正需要的時候進行創(chuàng)建
- [ ] 保護代理: 控制用戶的訪問權(quán)限
- [ ] 智能引用代理: 提供對目標對象提供額外的服務(wù)(火車票代售處)
智能引用代理:

靜態(tài)代理
- 靜態(tài)代理:代理和被代理對象在【代理之前】都是【確定】的。他們都實現(xiàn)【相同的接口或者繼承相同的抽象類】
- 代理實現(xiàn)方法:
(1)繼承法:代理類直接【繼承】被代理類,實現(xiàn)其原有方法,并添加一些額外功能
(2)聚合方法:代理類實現(xiàn)【相同的功能接口:很重要,事項相同接口,不同代理也可以進行相互代理】,并在內(nèi)聲明一個被代理類的對象(類似封裝),通過內(nèi)部對象實現(xiàn)其原有方法,并添加額外功能

3、靜態(tài)代理的實現(xiàn)
(1)聚合代理優(yōu)于繼承代理。因為實現(xiàn)功能疊加的情況下,聚合代理通過相互代理可以實現(xiàn)功能重用,而繼承代理必須寫多個類來實現(xiàn)多功能疊加。
(2)靜態(tài)代理只能代理一種類型的被代理類,換個類型的就不行了,這需要動態(tài)代理
4、靜態(tài)代理的兩種實現(xiàn)方式對比(繼承方式和聚合方式)
案例--代理類功能的疊加
(1) 繼承的方式:如果使用繼承的方式來實現(xiàn)我們代理功能的疊加,我們的代理類會無限的膨脹下去。
(2) 聚合的方式:由于代理類和被代理類都實現(xiàn)了相同的接口,那么代理類的構(gòu)造參數(shù)就可以傳入該相同的接口,這樣在后面功能疊加的時候就可以傳入其他功能的代理類,因為他們都實現(xiàn)了相同的父接口。從而達到功能疊加的作用。

動態(tài)代理

- JDK動態(tài)代理
(1) 目的:動態(tài)產(chǎn)生代理,實現(xiàn)對【不同類】,【不同方法】的代理
(2) java動態(tài)代理類,位于java.lang.reflect包下,一般涉及兩個類:
(1)Interface InvocationHandler:該接口中僅定義了一個方法public object invoke(Object obj,Method method,Object[] args)
參數(shù):
obj:被代理類的對象
method:被代理的方法
args:被代理方法參數(shù)數(shù)組
返回值:
Object:方法返回值
(2)Proxy:該類即為動態(tài)代理類:
static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
參數(shù):
loader:被代理類的類加載器,通過被代理類.getClass().getClassLoader()得到
interfaces:實現(xiàn)的接口,通過getClass().getInterfaces()得到
h:invocationHandler
返回值:
返回代理類的一個實例
- 動態(tài)代理實現(xiàn)步驟:
(1)創(chuàng)建一個實現(xiàn)接口InvocationHandler的類,它必須實現(xiàn)invoke方法。
(2)創(chuàng)建被代理的類以及接口。
(3)調(diào)用Proxy的靜態(tài)方法,創(chuàng)建一個代理類。
newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
(4)通過代理調(diào)用方法。

CGLIB動態(tài)代理
-
JDK動態(tài)代理與CGLIB動態(tài)代理之間的區(qū)別
- CGLIB:是一個強大的開源項目,可以在運行期擴展Java類與實現(xiàn)Java接口
- JDK動態(tài)代理實現(xiàn)思路
實現(xiàn)功能:通過Proxy的newProxyInstance返回代理對象
(1)聲明一段源碼(動態(tài)產(chǎn)生代理)
(2)編譯源碼(JDK Compiler API),產(chǎn)生新的類(代理類)
(3)將這個類load到內(nèi)存當中,產(chǎn)生一個新的對象(代理對象)
(4)return 代理對象
3. 總結(jié)


1、代理概念、分類及應(yīng)用場景
為其他對象設(shè)置總代理,以控制對這個對象的訪問;
代理對象起到了中介的作用,去掉了某些功能,或增加了些額外的服務(wù)。
四類:
Remote Proxy -- 客戶端服務(wù)器的模式
Virtual Proxy -- 資源消耗很大,或復(fù)雜的對象,需要延遲,需要時創(chuàng)建,
Protect Proxy -- 保護和控制權(quán)限
Smart Reference Proxy -- 提供額外服務(wù)。
為什么只講智能引用代理?
使用得多:日志處理、權(quán)限管理、事務(wù)處理...
靜態(tài)代理(繼承、聚合)
JDK動態(tài)代理實現(xiàn)日志處理的功能
模擬JDK動態(tài)代理實現(xiàn):在代理類Proxy和被代理類RealSubject之間,加入了invocationHandler。
調(diào)用jar包中某個類的方法,不能改源碼,AOP面向切面,增加額外事務(wù)邏輯。
適配器模式
適配器模式定義:
將一個類的接口,轉(zhuǎn)換成期望的另外一個借口,使得由于接口不兼容而不能一起工作的那些類可以一起工作。
適配器模式: 構(gòu)成
構(gòu)成:客戶端、目標接口、原本接口、具體請求

適配器模式分類
- 組合

-
繼承
比較

作用

行為型模式
觀察者模式
1. 認識觀察者模式
(1)定義:
定義對象件的一種一對多的依賴關(guān)系,當一個對象的狀態(tài)發(fā)生改變時,所有依賴它的對象都會得到通知并且自動更新,
(2)流程圖:

2. 實現(xiàn)的兩種方式:推模型和拉模型
- 結(jié)構(gòu)

- 觀察者模式通用代碼
步驟:
(1)目標對象的定義
(2)具體的目標對象的定義
(3)觀察者接口的定義
(4)觀察者的具體實現(xiàn)
3. 利用Java提供的觀察者實現(xiàn)
1. 認識觀察者模式
(1)目標與觀察者之間的關(guān)系:一對一、一對多、多對一等。
(2)單向依賴:觀察者依賴目標,而不是目標依賴觀察者,觀察者是被動的,目標是主動的。
(3)命名建議:
1、目標接口的定義,建議在名稱后面跟Subject;
2、觀察者接口的定義,建議在名稱后面跟Observer;
3、觀察者接口的更新方法,建議名稱為update,參數(shù)的個數(shù)及類型不受限制。
(4)觸發(fā)通知的時機:目標對象的狀態(tài)發(fā)生維護之后觸發(fā)。(比如:先賦值內(nèi)容再通知是對的,而反過來就會出現(xiàn)問題)
(5)觀察者模式調(diào)用時序:見觀察者模式調(diào)用時序圖I、II。
(6)通知的順序:不確定,平行的,沒有相互依賴關(guān)系。
-
準備階段
-
運行階段
2. 實現(xiàn)的兩種方式:推模型和拉模型
觀察者模式兩種模式:
-
推模型:目標對象主動向觀察者推送目標的詳細信息 ; 推送的信息通常是目標信息的全部或部分信息。
-
拉模型:目標對象在通知觀察者的時候,只傳遞少量信息 ;如果觀察者需要更具體的信息,由觀察者主動到目標對象中獲取,相當于是觀察者從目標對象中拉數(shù)據(jù);一般這種模型的實現(xiàn)中,會把目標對象自身通過update方法傳遞給觀察者。
兩種模型的比較:
推模型是假定目標對象知道觀察著需要的數(shù)據(jù)。
拉模型是目標對象不知道觀察著具體需要什么數(shù)據(jù),因此把自身傳給觀察者,由觀察者來取值。
推模型會使觀察者對象難于復(fù)用。
拉模型下,update方法的參數(shù)是目標對象本身,基本上可以適應(yīng)于各種情況的需要。
Java 實現(xiàn) VS 自己實現(xiàn)的對比四點:
(1)不需要再定義觀察者和目標接口(JDK已經(jīng)定義)。
(2)具體的目標實現(xiàn)里面不需要再維護觀察者的注冊信息,Java中的Observable類里面已經(jīng)實現(xiàn)。
(3)觸發(fā)通知的方式有一點變化,要先調(diào)用setChanged方法,這個是Java為了幫助實現(xiàn)更精確的觸發(fā)控制而提供的功能。
(4)具體觀察者的實現(xiàn)里面,update方法其實能同時支持推模型和拉模型,這個Java在定義的時候,已經(jīng)考慮。
4. 簡述觀察者優(yōu)缺點
| 優(yōu)點: | 缺點點: |
|---|---|
| 1. 觀察者模式實現(xiàn)了觀察者和目標之間的抽象耦合 2. 觀察者模式實現(xiàn)了動態(tài)聯(lián)動 3. 觀察者模式支持廣播通信 | 可能會引起無謂的操作。 |
5. 何時使用觀察者模式
使用觀察者模式的場景 --- 觸發(fā)聯(lián)動(本質(zhì))
1、當一個抽象模型有兩個方面,其中一個方面的操作依賴于另一個方面的狀態(tài)變化
2、如果更改一個對象的時候,需要同時連帶改變其他的對象,而且不知道究竟應(yīng)該有多少對象需要被連帶改變
3、當一個對象必須通知其他的對象,但是你又希望這個對象和其他被通知的對象是松散耦合的
6. 觀察者模式的衍生
觀察者模式——區(qū)別對待觀察者場景問題
- 需求總結(jié)

- 解決思路
(1)情況之一:如果天氣是晴天,按照黃明的女朋友需要下雨的條件,黃明的老媽需要下雨或下雪的條件,則她們倆就都不需要通知了。
(2)情況之二:如果天氣是下雨,則黃明的女朋友需要通知,而黃明的老媽也需要通知。
(3)情況之三:如果天氣是下雪,則只需要通知黃明的老媽。 -
實現(xiàn)步驟:
區(qū)別對待觀察者模式中,目標父類不實現(xiàn)通知方法,在子類中實現(xiàn)有區(qū)別的通知方法。
狀態(tài)變更調(diào)用通知方法,通知方法調(diào)用觀察者,同時回調(diào)目標對象
責任鏈模式
1. 什么是責任鏈模式
將接收者對象連成一條鏈,并在該鏈上傳遞請求,直到有一個接收者對象處理它。通過讓更多對象有機會處理請求,避免了請求發(fā)送者和接收者之間的耦合。

2. 如何實現(xiàn)責任鏈模式
流程是 顧客申請折扣,觸發(fā)priceHandler對請求價格的處理,在處理價格之前通過工廠方法創(chuàng)建了一個priceHandler的實例,如果實例處理不了折扣,觸發(fā)后繼,然后調(diào)用工廠設(shè)置后繼并創(chuàng)建新的PriceHandler來處理折扣,還是處理不了繼續(xù)申請,直到成功。
3. 責任鏈模式如何解耦
加入了新的能夠折扣處理的成員lead類繼承了PriceHandler
對工廠方法進行了改動 添加了lead的實例,以及給lead設(shè)置了后繼Successor
1、OO的一些原則:
2、如 單一職責原則 : 設(shè)置一個接口時,應(yīng)該只將與這個接口業(yè)務(wù)相關(guān)的方法放在接口之中。
3、工場方法的實質(zhì)在用返回返回的是一個接口,而不是一個實例對象。
4、用到責任鏈,總會用到工廠
將指定的方法移到某個文件中的快捷鍵操作方式:
選中方法名——Refactor——Move——選擇需要移動到的目標文件——確定
責任鏈模式:使用了自身對象后繼

解耦---

責任鏈模式真的好嗎
- 開閉原則(OO中的一個基本原則):
對擴展開放,對變更關(guān)閉,即是如果有一個業(yè)務(wù)變更,希望新增一個類,而非修改原有代碼來滿足業(yè)務(wù)需求.
- 責任鏈模式的執(zhí)行性能:
當有請求到達時會從責任鏈頭部開始遍歷整條責任鏈,直到有一個處理器處理了請求,或者是整個鏈條遍歷完成,在這過程中性能的損耗體現(xiàn)在兩個方面.
(1)是時間,相對于單個Handler處理請求的時間而言,整個鏈條的遍歷過程會消耗更多的時間.
(2) 是內(nèi)存,使用責任鏈模式創(chuàng)建了大量對象來表示處理器對象,但僅僅使用了其中的少部分,剩余的大部分處理器都僅僅作為一個過客.
4. 責任鏈模式的應(yīng)用
責任鏈模式在日常編碼中可能不是經(jīng)常用到的模式,但不管是前端還是后端工程師都可能天天接接觸到責任鏈模式.
后端:Java中的異常處理;
前端:JavaScript Event Model;
Java Web:FilterChain in Web(不純的COR)
1. JAVA中的異常處理機制是使用責任鏈模式
2. JavaScript的事件模式也是責任鏈模式
3. JAVAEE中的Filter
(1)JAVAEE中的Filter經(jīng)常可以在請求到達核心代碼之前對它進行攔截并作出一些操作,當多個Filter存在的時候就共同構(gòu)成了一個FilterChain,FilterChain不是一個存的責任鏈,責任鏈模式中只能有一個對象來處理請求,而FilterChain中可以有多個對象同時處理請求.
5. 各個模式間的聯(lián)系
設(shè)計模式的學(xué)習一定要結(jié)合OO的基本原則
面向?qū)ο蟮奈宕笤瓌t:
- 單一職責原則
- 開放封閉原則(對擴展開放,對變更封閉)
- 依賴倒置原則(核心是依賴抽象)
- 接口隔離原則
- Liskov替換原則(里氏替換原則)

策略模式
1. 什么是策略模式
策略模式將可變的部分從程序中抽象分離成算法接口,在該接口下分別封裝一系列算法實現(xiàn)。
并使他們可以互相替換。
從而導(dǎo)致客戶端程序獨立于算法的改變。

2. 策略模式如何實現(xiàn)
鴨子應(yīng)用的更新需求

鴨子飛行
方案一:繼承

方案二:抽象方法

方案三:組合

1.Favor composition over inheritance:復(fù)合(組合)優(yōu)先于繼承。多用組合,少用繼承。

2.組合定義:在類中增加一個私有域,引用另一個已有的類的實例,通過調(diào)用引用實例的方法從而獲得新的功能,這種設(shè)計被稱作組合(復(fù)合)(意思就是:得到其他類的對象,使用這個對象的方法。)

3. 策略模式總結(jié)
一、策略模式設(shè)計原則:
- 找出應(yīng)用中需要變化的部分,把他們獨立出來,不要和那些不需要變化的代碼混在一起;
將不變的東西抽象為接口,而變化的部分交給實現(xiàn)去做,具體而言,鴨子飛行的行為是千變?nèi)f化的,但是鴨子具有飛行行為本身是不變的,我們將不變的部分抽象為飛行策略接口,而將具體的飛行行為交給實現(xiàn)去處理。 - 面向接口編程,而不是面向?qū)崿F(xiàn)編程。
- 多用組合,少用繼承。
二、策略模式的實現(xiàn):
- 通過分離變化得出策略接口Strategy。
- 編寫Strategy的實現(xiàn)類。
- 客戶端程序“有一個”Strategy。
- 在客戶程序中選擇/組裝正確的Strategy實現(xiàn)。
三、策略模式的優(yōu)點:
- 使用了組合,使架構(gòu)更加靈活。
- 富有彈性,可以較好的應(yīng)對變化(開閉原則)。
- 更好的代碼復(fù)用性(相對于繼承)。
- 消除了大量的條件語句。
四、策略模式的缺點:
- 客戶代碼需要了解每個策略實現(xiàn)的細節(jié),不然就會使得實現(xiàn)有可能有不正確的行為。
- 隨著時間的推移,策略接口會急劇膨脹,增加了對象的數(shù)目。
五、策略模式的適用場景:
- 許多相關(guān)的類僅僅是行為差異,將差異的共享分離出來成為一個策略接口,而這些相關(guān)的類便成為其算法家族的成員。
- 運行時選取不同的算法變體。
- 通過條件語句在多個分支中選取一個,使用策略模式使得代碼更加簡潔。
4. 實際案例分享
模板方法模式
1. 什么是模板方法模式
(1) 模板模式
定義了一個操作中的算法骨架,而將一些步驟延遲到子類中實現(xiàn),使得子類在不改變一個算法結(jié)構(gòu)的同時,就重新定義該算法的特定步驟.

=>

(2) 生活案例——飲料的調(diào)制方法

=>

2. 如何實現(xiàn)模板方法模式
- 定義抽象基類
(1)實現(xiàn)方法(通用共同屬性)
(2)抽象方法(延遲方法)
(3)鉤子方法(擴展點)
(4)模板方法(一定要用final因為要禁止子類對方法框架的覆寫) - 子類
模板方法的基本實現(xiàn)
思想
1、一份算法框架,大家共同遵守
2、 算法框架中分離出變與不變的部分
3、將變化的算法,延遲實現(xiàn)(交由具體的子類實現(xiàn))
基本實現(xiàn)
1、用一個抽象基類,一個public final方法定義好算法框架
2、不變的部分,用private方法加以實現(xiàn)。(基本方法)
3、變化的部分,用protected abstract加以定義(抽象方法)
使用
1、面向接口編程
2、傳入實際的實現(xiàn)子類給接口變量
3、接口變量調(diào)用框架方法
用鉤子(Hook)函數(shù)實現(xiàn)子類對算法框架個性化的擴展
1、思想
框架通過提供一個個的鉤子,使框架具備了更大的靈活性。不想執(zhí)行算法框架中的某些個步驟,我們可以脫鉤,如果想執(zhí)行的話,我們可以掛鉤。
2、實現(xiàn)
在抽象類中,提供protected鉤子方法。這是個實現(xiàn)的或空的方法。這樣子類就可以選擇覆寫-持鉤,也可以選擇不覆寫-脫勾。
3、使用
提供一個isXXX類型的鉤子方法。用該方法控制算法框架中
4、某個步驟是否執(zhí)行
子類不覆寫這個方法,就是脫鉤,仍按框架邏輯執(zhí)行,一旦覆寫,就是掛鉤,將改變框架算法方向,按子類邏輯執(zhí)行。
3. 模板方法模式的特點
一、模板方法模式的實現(xiàn)要素:
準備一個抽象類,將部分邏輯以具體方法的形式實現(xiàn),然后聲明一些抽象方法交由子類實現(xiàn)剩余邏輯,用鉤子方法給予子類更大的靈活性。最后將方法匯總構(gòu)成一個不可改變的模板方法。
二、從類的角度看:
(1)抽象基類
1、基本方法。
2、抽象方法【只知道具體原則,而不知道實現(xiàn)細節(jié),需要將其延遲到子類中實現(xiàn)的一些步驟】。
3、可選鉤子(Hook,鉤子函數(shù),提供一個默認或空的實現(xiàn)。具體的子類可以自行決定是否掛鉤以及如何掛鉤)。
4、Template方法(final 使其不能被子類所覆寫 模板方法模式要遵循的原則:子類可以替換掉父類中的可變邏輯,但不能改變整體邏輯結(jié)構(gòu)))。
(2)具體子類
1、實現(xiàn)基類中的抽象方法。
2、覆蓋鉤子方法。
三、模板方法的優(yōu)點:
(1)封裝性好。(2)復(fù)用性好。(3)屏蔽細節(jié)。(4)便于維護。
四、模板方法的缺點:
(1)繼承限制(Java語言是單繼承語言),單繼承會使得更多情況不可用,新類引入困難。
五、模板方法模式的適用場景:
(1)算法或操作遵循相似的邏輯。
(2)重構(gòu)時(把相同的代碼抽取到父類中)。
(3)重要、復(fù)雜的算法,核心算法設(shè)計為模板方法。
4. 模板方法模式在項目中的應(yīng)用
電信聯(lián)通移動三大運營商日志需求分析

解決方案1

解決方案1.2 提供擴展點,使用鉤子函數(shù)實現(xiàn)

















