摘要:孫臏心里一萬個草泥馬在奔騰,差點沒噎死自己滾一邊去,我們這盤跟他賽馬開始,策略模式上場。在設計模式之禪中的提出通過策略枚舉和反射機制對策略模式進行改良,膜拜了但是要添加或淘汰策略,還是得去對枚舉進行修改,也不符合開閉原則。
今天給大家說說田忌賽馬的故事。如有雷同,純屬巧合!話說在戰(zhàn)國時期,群雄割據,硝煙四起,茶余飯后還是少不了娛樂活動的,其中賽馬是最火爆的。一天,孫臏看到田忌像個死雞似的就知道肯定賽馬又輸給了齊威王,立馬抓住田忌去跟齊威王再賽一場。
孫臏:“小忌啊,哥哥看著你心疼啊,哥哥出對策幫你贏一盤如何?”。
田忌聽到之后高興得飛起,瞪大了兩只金魚眼“Really?只要能贏,我赴湯蹈火,以身相許又如何~”。
孫臏心里一萬個草泥馬在奔騰,差點沒噎死自己“滾一邊去,我們這盤跟他show hand!”賽馬開始,策略模式上場。此處應該有bgm“讓我們紅塵作伴活得瀟瀟灑灑 策馬奔騰共享人世繁華...呀啊呀啊,呀啊啊啊啊啊啊~”
一、策略模式 定義??定義一組算法,將每一個算法封裝起來,從而使它們可以相互切換。
特點??1)一組算法,那就是不同的策略。
??2)這組算法都實現了相同的接口或者繼承相同的抽象類,所以可以相互切換。
UML策略模式涉及到的角色有三個:
??- 封裝角色:上層訪問策略的入口,它持有抽象策略角色的引用。
??- 抽象策略角色:提供接口或者抽象類,定義策略組必須擁有的方法和屬性。
??- 具體策略角色:實現抽象策略,定義具體的算法邏輯。
二、實戰(zhàn)在跟齊威王比賽之前來分析下之前輸掉比賽的“策略”,首先來看封裝角色,代碼如下:
public class Context { private Strategy strategy; /** * 傳進的是一個具體的策略實例 * @param strategy */ public Context(Strategy strategy) { this.strategy = strategy; } /** * 調用策略 */ public void contextInterface() { strategy.algorithmLogic(); } }
Context持有Strategy的引用,并且提供了調用策略的方法,很清晰。
再來抽象策略角色,定義了策略組的方法,代碼如下:
public interface Strategy { public void algorithmLogic(); }
輸掉比賽的“策略”也是一種策略,是具體策略角色類,來看代碼:
public class ConcreteStrategyA implements Strategy{ @Override public void algorithmLogic() { // 具體的算法邏輯(輸了比賽) System.out.println("第一場:上等馬vs上等馬 第二場:中等馬vs中等馬 第三場:下等馬vs下等馬 賽果:輸!"); } }
看到這里,孫臏一陣無語,慘不忍睹也得看結果的,客戶端代碼如下:
public class Client { public static void main(String[] args) { // 操控比賽,這場要輸 Context context = new Context(new ConcreteStrategyA()); context.contextInterface(); } }
兩句代碼,傳入具體策略對象,調用策略入口方法,運行結果如下:
第一場:上等馬vs上等馬 第二場:中等馬vs中等馬 第三場:下等馬vs下等馬 賽果:輸!
田忌跟孫臏說:“臏哥,我怕!”,孫臏:“不用怕,哥哥在!”。
田忌找到齊威王“大王,我們再...再再來一盤,輸了請吃飯”
瞅瞅孫臏出的策略,一睹軍事家的風采,“贏”的具體策略類代碼如下:
public class ConcreteStrategyB implements Strategy{ @Override public void algorithmLogic() { // 贏 System.out.println("第一場:下等馬vs上等馬 第二場:上等馬vs中等馬 第三場:中等馬vs下等馬 賽果:贏!"); } }
再來看客戶端的代碼:
public class Client { public static void main(String[] args) { // 操控比賽,這場要贏,哈哈哈 Context context = new Context(new ConcreteStrategyB()); context.contextInterface(); } }
運行結果如下:
第一場:下等馬vs上等馬 第二場:上等馬vs中等馬 第三場:中等馬vs下等馬 賽果:贏!
田忌拍爛手掌,重要的是今天晚飯有著落了,還要對臏哥哥以身相許的......
三、策略模式的優(yōu)缺點 優(yōu)點1)良好的擴展性。增加一種策略,只要實現接口,寫上具體邏輯就可以了。當舊策略不需要時,直接剔除就行。
2)良好的封裝性。策略的入口封裝在Context封裝類中,客戶端只要知道使用哪種策略就傳哪種策略對象就可以了。
3)避免了像簡單工廠模式這樣的多重條件判斷。
缺點1)客戶端必須了解策略組的各個策略,并且決定使用哪一個策略,也就是各個策略需要暴露給客戶端。
2)如果策略增多,策略類的數量就會增加。
四、擴展上面說到策略模式有一個缺點,就是所有的策略都必須暴露出去,讓客戶端自行選擇策略使用。現在來改善這一缺陷,而改善這個缺陷需要跟簡單工廠模式結合混編,繼續(xù)往下看。
當然,軍事家孫臏也會想到這一點,怎么可能會把自己的套路全都暴露給別人呢,那還怎么玩是吧。不過,歷史上并沒有說孫臏改善了這點,現在是我來改善這個缺陷,哈哈哈~
策略工廠思考一個問題,策略暴露了,改善就是把策略隱藏起來,而工廠模式就有這個效果,客戶端不需要知道策略具體是什么,只知道結果就好。OK,那么我們可以使用工廠模式把策略當做產品生成嗎?答案是肯定的。策略模式的入口就在Context封裝類,可以從這個角色做手腳。先看代碼:
public class Context { private Strategy strategy; // 把創(chuàng)建策略放在封裝角色內,客戶端只需要知道結果 public void factory(String strategyType) { if (strategyType.equals("WIN")) { strategy = new ConcreteStrategyB(); } else if (strategyType.equals("LOSE")) { strategy = new ConcreteStrategyA(); } } /** * 調用策略 */ public void contextInterface() { strategy.algorithmLogic(); } }
代碼很簡單,增加了factory的方法,這個方法作用就是創(chuàng)建策略對象。這樣,客戶端就不需要去理解具體的策略,只需知道具體策略的結果就好。看看客戶端代碼:
public class Client { public static void main(String[] args) { Context context = new Context(); context.factory("LOSE"); context.contextInterface(); } }總結
注意策略模式和工廠方法模式的區(qū)別,在前面工廠方法模式中有說到,這里就不再闡述。策略模式本身也相對比較簡單,重點在它的擴展以及其它模式的對比,分析各自的優(yōu)缺點。來看看策略工廠這樣的模式存在缺點嗎?很明顯,如果需要添加或者淘汰一種策略,Context就必須修改,這并不符合開閉原則。在《設計模式之禪》中的提出通過策略枚舉和反射機制對策略模式進行改良,膜拜了~但是要添加或淘汰策略,還是得去對枚舉進行修改,也不符合開閉原則。根據自己項目情況,選擇最適合自己項目的模式。下一篇是責任鏈模式,歡迎繼續(xù)關注,goodbye!
設計模式Java源碼GitHub下載:https://github.com/jetLee92/DesignPattern
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/67933.html
摘要:工廠方法模式和策略的模式有什么區(qū)別區(qū)別在于,策略模式強調的是提供不同的策略方案,而工廠方法模式強調的是產品本身。 女朋友dodo鬧脾氣,氣勢洶洶的說我要吃雪糕。筆者心里啊樂滋滋的,一支雪糕就能哄回來,不亦樂乎?! 但是,雪糕買回來了,她竟然說不想吃雪糕了,突然想吃披薩。呵呵了,憋了一股勁沒問題,又屁顛屁顛的去把披薩買回來。 世事難料,dodo同學又放大招了,披薩太上火了,我要吃芝士蛋糕...
摘要:我們今天也來做一個萬能遙控器設計模式適配器模式將一個類的接口轉換成客戶希望的另外一個接口。今天要介紹的仍然是創(chuàng)建型設計模式的一種建造者模式。設計模式的理論知識固然重要,但 計算機程序的思維邏輯 (54) - 剖析 Collections - 設計模式 上節(jié)我們提到,類 Collections 中大概有兩類功能,第一類是對容器接口對象進行操作,第二類是返回一個容器接口對象,上節(jié)我們介紹了...
閱讀 1655·2023-04-25 16:29
閱讀 961·2021-11-15 11:38
閱讀 2300·2021-09-23 11:45
閱讀 1428·2021-09-22 16:03
閱讀 2545·2019-08-30 15:54
閱讀 1207·2019-08-30 10:53
閱讀 2606·2019-08-29 15:24
閱讀 1107·2019-08-26 12:25