深入理解Java設(shè)計(jì)模式之策略模式
一、什么是策略模式
策略模式定義了一系列算法,并將每個算法封裝起來,使他們可以相互替換,且算法的變化不會影響到使用算法的客戶。需要設(shè)計(jì)一個接口,為一系列實(shí)現(xiàn)類提供統(tǒng)一的方法,多個實(shí)現(xiàn)類實(shí)現(xiàn)該接口,設(shè)計(jì)一個抽象類(可有可無,屬于輔助類),提供輔助函數(shù)。
策略模式定義和封裝了一系列的算法,它們是可以相互替換的,也就是說它們具有共性,而它們的共性就體現(xiàn)在策略接口的行為上,另外為了達(dá)到最后一句話的目的,也就是說讓算法獨(dú)立于使用它的客戶而獨(dú)立變化,我們需要讓客戶端依賴于策略接口。
一種很簡單的解釋,在我們的開發(fā)過程中,經(jīng)常會遇到大量的if...else或者switch...case語句,當(dāng)這些語句在開發(fā)中只是為了起到分流作用,這些分流和業(yè)務(wù)邏輯無關(guān),那么這個時候就可以考慮用策略模式。
二、策略模式的結(jié)構(gòu)
這個模式涉及到三個角色:
上下文環(huán)境(Context
)角色:持有一個Strategy的引用。
抽象策略(Strategy
)角色:這是一個抽象角色,通常由一個接口或抽象類實(shí)現(xiàn)。此角色給出所有的具體策略類所需的接口。
具體策略(ConcreteStrategy
)角色:包裝了相關(guān)的算法或行為
三、策略模式的應(yīng)用場景
舉一個例子,商場搞促銷--打8折,滿200送50,滿1000送禮物,這種促銷就是策略。
再舉一個例子,dota里面的戰(zhàn)術(shù),玩命四保一,三偽核體系,推進(jìn)體系,大招流體系等,這些戰(zhàn)術(shù)都是一種策略。
應(yīng)用場景:
1、 多個類只區(qū)別在表現(xiàn)行為不同,可以使用Strategy模式,在運(yùn)行時動態(tài)選擇具體要執(zhí)行的行為。
2、 需要在不同情況下使用不同的策略(算法),或者策略還可能在未來用其它方式來實(shí)現(xiàn)。
3、 對客戶隱藏具體策略(算法)的實(shí)現(xiàn)細(xì)節(jié),彼此完全獨(dú)立。
四、策略模式的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
1、結(jié)構(gòu)清晰,把策略分離成一個個單獨(dú)的類「替換了傳統(tǒng)的 if else」2、代碼耦合度降低,安全性提高「各個策略的細(xì)節(jié)被屏蔽」
缺點(diǎn):
1、客戶端必須要知道所有的策略類,否則你不知道該使用那個策略,所以策略模式適用于提前知道所有策略的情況下2、策略類數(shù)量增多(每一個策略類復(fù)用性很小,如果需要增加算法,就只能新增類)五、策略模式和簡單工廠模式的異同
在上篇文章已經(jīng)提過了,傳送地址:深入理解設(shè)計(jì)模式(二):簡單工廠模式
六、策略模式的實(shí)現(xiàn)
Strategy
類,定義所有支持的算法的公共接口
//Strategy類,定義所有支持的算法的公共接口 abstract class Strategy { //算法方法 public abstract void AlgorithmInterface(); }
oncreteStrategy
,封裝了具體的算法或行為,繼承于Strategy
//算法A class ConcreteStrategyA : Strategy { public override void AlgorithmInterface() { Console.WriteLine("算法A的實(shí)現(xiàn)"); } } //算法B class ConcreteStrategyB : Strategy { public override void AlgorithmInterface() { Console.WriteLine("算法B的實(shí)現(xiàn)"); } } //算法C class ConcreteStrategyC : Strategy { public override void AlgorithmInterface() { Console.WriteLine("算法C的實(shí)現(xiàn)"); } }
Context
,用一個ConcreteStrategy來配置,維護(hù)一個對Strategy對象的引用
//Context,用一個ConcreteStrategy來配置,維護(hù)一個對Strategy對象的引用 class Context { Strategy Strategy; public Context(Strategy Strategy) { this.Strategy = Strategy; } //上下文接口 public void ContextInterface() { Strategy.AlgorithmInterface(); } }
客戶端代碼
static void Main(string[] args) { Context Context; Context = new Context(new ConcreteStrategyA()); Context.ContextInterface(); Context = new Context(new ConcreteStrategyB()); Context.ContextInterface(); Context = new Context(new ConcreteStrategyC()); Context.ContextInterface(); Console.Read(); }
七、策略模式和簡單工廠模式的結(jié)合
改造后的Context
class Context { Strategy Strategy=null; public Context(string type) { switch (type) { case "A": ConcreteStrategyA A = new ConcreteStrategyA(); Strategy = A; break; case "B": ConcreteStrategyB B = new ConcreteStrategyB(); Strategy = B; break; case "C": ConcreteStrategyC C = new ConcreteStrategyC(); Strategy = C; break; } } //上下文接口 public void ContextInterface() { Strategy.AlgorithmInterface(); } }
改造后的客戶端代碼
static void Main(string[] args) { Context Context = new Context("這里是相應(yīng)的算法類型字符串"); Context.ContextInterface(); Console.Read(); }
對比下改造前后的區(qū)別不難看出,改造前客戶端需要認(rèn)識兩個類,Context和ConcreteStrategy。而策略模式和簡單工廠模式結(jié)合后,客戶端只需要認(rèn)識一個類Context,降低了耦合性。
八、策略枚舉的實(shí)現(xiàn)
我們可以使用枚舉在一個類中實(shí)現(xiàn)以上所有的功能及三種不同的角色,下面看看怎么通過枚舉來實(shí)現(xiàn)策略模式
public enum Calculator { ADD("+") { public int exec(int a, int b) { return a+b; } }, SUB("-") { public int exec(int a, int b) { return a-b; } }; public abstract int exec(int a, int b); //運(yùn)算符 private String value = ""; private Calculator(String value) { this.value = value; } public String getValue() { return value; } }
在枚舉類中,定義的抽象方法就像當(dāng)時之前的接口,每一個枚舉ADD SUB相當(dāng)是一個具體的實(shí)現(xiàn)類(策略角色),而整個枚舉類就是策略的分裝角色。
這是從網(wǎng)上copy的代碼,本人不怎么喜歡這么寫,總感覺違背了代碼規(guī)范。
九、總結(jié)
策略模式,實(shí)質(zhì)就是封裝了一些算法,讓算法可以互相替換,用戶可以自由選擇這些算法進(jìn)行操作。策略模式本身理解起來沒什么難點(diǎn),但是在實(shí)際應(yīng)用中其本身主要結(jié)合工廠模式一起使用。
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Graceful Response 構(gòu)建 Spring Boot 響應(yīng)
Graceful Response是一個Spring Boot技術(shù)棧下的優(yōu)雅響應(yīng)處理器,提供一站式統(tǒng)一返回值封裝、全局異常處理、自定義異常錯誤碼等功能,本文介紹Graceful Response 構(gòu)建 Spring Boot 下優(yōu)雅的響應(yīng)處理,感興趣的朋友一起看看吧2024-01-01SpringBoot項(xiàng)目速度提升之延遲初始化(Lazy Initialization)詳解
延遲初始化(Lazy?Initialization)是一種在需要時才創(chuàng)建或加載對象的策略,以減少啟動時間和資源消耗,本文就來講講延遲初始化的具體使用吧2023-05-05Struts2單選按鈕詳解及枚舉類型的轉(zhuǎn)換代碼示例
這篇文章主要介紹了Struts2單選按鈕詳解及枚舉類型的轉(zhuǎn)換代碼示例,分享了相關(guān)代碼示例,小編覺得還是挺不錯的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-02-02Java實(shí)現(xiàn)按照大小寫字母順序排序的方法
這篇文章主要介紹了Java實(shí)現(xiàn)按照大小寫字母順序排序的方法,涉及java數(shù)組遍歷、編碼轉(zhuǎn)換、判斷等相關(guān)操作技巧,需要的朋友可以參考下2017-12-12SpringMVC源碼解析之消息轉(zhuǎn)換器HttpMessageConverter
本篇文章主要介紹了SpringMVC源碼解析之消息轉(zhuǎn)換器HttpMessageConverter ,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11SpringCloud項(xiàng)目中Feign組件添加請求頭所遇到的坑及解決
這篇文章主要介紹了SpringCloud項(xiàng)目中Feign組件添加請求頭所遇到的坑及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04