1、簡介
1.1 繼承帶來的擴充和複用問題
1.2 進一步改進,利用接口
1.3 進一步改進,政策模式
2、适用場景
3、優點
4、缺點
5、代碼示例
6、源碼分析
6.1 spring中應用
7、政策模式總結、類圖
相關參考博文:
部落格園:
spring2sun:設計模式系列
定義了一系列的算法,把他們封裝起來,他們互相之間可以替換,某個算法的調整或者新增不會影響其他的算法,是在執行期間來選擇具體的算法,使用什麼算法被推遲到運作時,使得系統更加靈活,複用性更高,該模式可以減少if else的數量,屬于行為型。
context封裝角色
也叫做上下文角色,起承上啟下封裝作用,屏蔽高層子產品對政策、算法的直接通路,封裝可能存在的變化。
strategy抽象政策角色
政策、算法家族的抽象,通常為接口,定義每個政策或算法必須具有的方法和屬性。
concreatestrategy
實作抽象政策中的操作,該類有具體的算法。
繼承作為面向對象的三大要素(封裝、繼承、多态)之一為什麼會帶來問題,問題如何解決然後形成一種設計模式,head frist設計模式書中以鴨子作為例子講解什麼情況下繼承的方式會帶來問題。首先有各種各樣的鴨子,那麼自然想到各種鴨子繼承自一個父類:父類為duck,現有綠頭鴨greenheadduck和紅頭鴨redheadduck:
父類中所有鴨子都會呱呱叫(quack)和遊泳(swin),外觀卻不一樣是以display為抽象方法,讓繼承它的子類重寫。現在需要新增一種鴨子,但這個鴨子是一個玩具橡皮鴨,我們按照繼承的方式則橡皮鴨實作代碼如下:
因為橡皮鴨是不會像其他鴨子那樣叫的,是以上面代碼我們需要重寫qucak覆寫橡皮鴨叫的方式可。現在有一個需求,需要讓鴨子飛起來,按照繼承的方式我們給父類duck添加 fly方法即可讓所有鴨子飛起來。但是問題出現了,橡皮鴨是不會飛的,于是我們可以像覆寫qucak方法一樣在rubberduck中覆寫fly方法。
到這裡我們已經發現了繼承帶來的問題:
代碼在多個子類中重複。
很難知道所有子類的行為。
運作的子類行為不容易改變。
改變會牽一發動全身,引起其他子類不想要的改變。
每當有新的子類出現,就要檢查是不是需要覆寫父類方法。比如再加一種木頭玩具的鴨子(decoyduck),那麼木頭鴨子不會叫也不會飛,我們是不是需要覆寫叫和飛的方法。
由于quack和fly有可能變化,是以我們将quack 和fly抽象成接口,能夠叫和飛行的鴨子才按需求繼承接口自己實作方法。
利用接口可以解決一部分問題(不在需要重寫不需要的方法),但是卻會造成代碼無法複用,因為接口不具有實作,我們要在每種子類中寫fly和quack。比如要在紅頭綠頭中寫"呱呱叫",要在橡皮鴨中寫"吱吱叫"。
經過上面的分析可以引出設計模式的兩個原則:
把會變化的部分封裝起來,讓其他部分不會受到影響。
針對接口程式設計,而不是針對實作。
通過第一個設計原則我們可以取出易于變化的部分:鴨子的飛行行為(fly)和呱呱叫的行為(quack)。通過第二個設計原則我們知道需要利用接口代表每個行為,比如flybehavior與quackbehavior,而行為的每個實作都将實作其中的一個接口。這樣鴨子類就不會負責實作flybehavior與quackbehavior,而是由行為類來專門實作,不會綁死在鴨子的子類中。
而"針對接口程式設計"的意思是"針對超類型程式設計"。可以明确地說明變量的聲明類型應該是超類,這意味着我們在duck父類中聲明的行為變量為 flybehavior,quackbehavior,“針對接口程式設計"的關鍵就在于面向對象三要素之一的"多态”,由于多态我們才能在調用超類的方法時執行的是實作類或子類的方法。是以我們改造之前寫的duck類,删除fly()和quack(),加入flybehavior和quackbehavior變量,并用另外兩個方法performfly()和performquack()來執行兩個行為。
編寫相關類并測試:
如上測試我們在鴨子子類中通過構造方法執行個體化行為類,但建立了一堆動态的功能沒有用到,是否可以動态的設定行為而不是在構造函數裡面執行個體化。是以我們還可以加入兩個設定行為的方法 setflybehavior和setquackbehavior,再次測試動态設定行為。
系統有很多類,但是他們的差別隻是行為不同
一個系統需要動态的在幾個算法中選擇一種
多個類隻有在算法或行為上稍有不同的場景
算法需要自由切換的場景
需要屏蔽算法規則的場景
注意事項:
具體政策數量超過4個,則需要考慮使用混合模式。
1、可以減少ifelse語句
2、提高算法的保密性和安全性
3、符合開閉原則
1、用戶端需要知道所有政策類,自己決定使用哪個政策類
2、類的數量增加
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-bhcvnhwc-1608389668751)(https://img.hacpai.com/file/2019/07/image-447d0de5.png?imageview2/2/w/768/format/jpg/interlace/1/q/100)]
訂單政策接口
支付寶下單政策
微信下單政策
空政策類
訂單類型枚舉類
下單工廠類
測試類
輸出結果為:
resource
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-w5uzzxjg-1608389668755)(https://img.hacpai.com/file/2019/07/image-cd73df82.png?imageview2/2/w/768/format/jpg/interlace/1/q/100)]
如圖,有不同的政策類,
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-lnpd49zr-1608389668756)(https://img.hacpai.com/file/2019/07/image-2ec69237.png?imageview2/2/w/768/format/jpg/interlace/1/q/100)]
instantiationstrategy從名字上就可以看出是政策模式,
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-kfyog01n-1608389668758)(https://img.hacpai.com/file/2019/07/image-66f96b08.png?imageview2/2/w/768/format/jpg/interlace/1/q/100)]
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-00o1umwv-1608389668759)(https://img.hacpai.com/file/2019/07/image-57873357.png?imageview2/2/w/768/format/jpg/interlace/1/q/100)]
也可以通過set方法來進行配置。
政策模式:定義了算法簇,分别封裝起來,讓它們之間可以互相替換,此模式讓算法的變化獨立于使用算法的客戶