深入理解Java設計模式之策略模式
一、什麼是策略模式
策略模式定義瞭一系列算法,並將每個算法封裝起來,使他們可以相互替換,且算法的變化不會影響到使用算法的客戶。需要設計一個接口,為一系列實現類提供統一的方法,多個實現類實現該接口,設計一個抽象類(可有可無,屬於輔助類),提供輔助函數。
策略模式定義和封裝瞭一系列的算法,它們是可以相互替換的,也就是說它們具有共性,而它們的共性就體現在策略接口的行為上,另外為瞭達到最後一句話的目的,也就是說讓算法獨立於使用它的客戶而獨立變化,我們需要讓客戶端依賴於策略接口。
一種很簡單的解釋,在我們的開發過程中,經常會遇到大量的if…else或者switch…case語句,當這些語句在開發中隻是為瞭起到分流作用,這些分流和業務邏輯無關,那麼這個時候就可以考慮用策略模式。
二、策略模式的結構
這個模式涉及到三個角色:
上下文環境(Context
)角色:持有一個Strategy的引用。
抽象策略(Strategy
)角色:這是一個抽象角色,通常由一個接口或抽象類實現。此角色給出所有的具體策略類所需的接口。
具體策略(ConcreteStrategy
)角色:包裝瞭相關的算法或行為
三、策略模式的應用場景
舉一個例子,商場搞促銷–打8折,滿200送50,滿1000送禮物,這種促銷就是策略。
再舉一個例子,dota裡面的戰術,玩命四保一,三偽核體系,推進體系,大招流體系等,這些戰術都是一種策略。
應用場景:
1、 多個類隻區別在表現行為不同,可以使用Strategy模式,在運行時動態選擇具體要執行的行為。
2、 需要在不同情況下使用不同的策略(算法),或者策略還可能在未來用其它方式來實現。
3、 對客戶隱藏具體策略(算法)的實現細節,彼此完全獨立。
四、策略模式的優缺點
優點:
1、結構清晰,把策略分離成一個個單獨的類「替換瞭傳統的 if else」2、代碼耦合度降低,安全性提高「各個策略的細節被屏蔽」
缺點:
1、客戶端必須要知道所有的策略類,否則你不知道該使用那個策略,所以策略模式適用於提前知道所有策略的情況下2、策略類數量增多(每一個策略類復用性很小,如果需要增加算法,就隻能新增類)五、策略模式和簡單工廠模式的異同
在上篇文章已經提過瞭,傳送地址:深入理解設計模式(二):簡單工廠模式
六、策略模式的實現
Strategy
類,定義所有支持的算法的公共接口
//Strategy類,定義所有支持的算法的公共接口 abstract class Strategy { //算法方法 public abstract void AlgorithmInterface(); }
oncreteStrategy
,封裝瞭具體的算法或行為,繼承於Strategy
//算法A class ConcreteStrategyA : Strategy { public override void AlgorithmInterface() { Console.WriteLine("算法A的實現"); } } //算法B class ConcreteStrategyB : Strategy { public override void AlgorithmInterface() { Console.WriteLine("算法B的實現"); } } //算法C class ConcreteStrategyC : Strategy { public override void AlgorithmInterface() { Console.WriteLine("算法C的實現"); } }
Context
,用一個ConcreteStrategy來配置,維護一個對Strategy對象的引用
//Context,用一個ConcreteStrategy來配置,維護一個對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(); }
七、策略模式和簡單工廠模式的結合
改造後的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("這裡是相應的算法類型字符串"); Context.ContextInterface(); Console.Read(); }
對比下改造前後的區別不難看出,改造前客戶端需要認識兩個類,Context和ConcreteStrategy。而策略模式和簡單工廠模式結合後,客戶端隻需要認識一個類Context,降低瞭耦合性。
八、策略枚舉的實現
我們可以使用枚舉在一個類中實現以上所有的功能及三種不同的角色,下面看看怎麼通過枚舉來實現策略模式
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); //運算符 private String value = ""; private Calculator(String value) { this.value = value; } public String getValue() { return value; } }
在枚舉類中,定義的抽象方法就像當時之前的接口,每一個枚舉ADD SUB相當是一個具體的實現類(策略角色),而整個枚舉類就是策略的分裝角色。
這是從網上copy的代碼,本人不怎麼喜歡這麼寫,總感覺違背瞭代碼規范。
九、總結
策略模式,實質就是封裝瞭一些算法,讓算法可以互相替換,用戶可以自由選擇這些算法進行操作。策略模式本身理解起來沒什麼難點,但是在實際應用中其本身主要結合工廠模式一起使用。
本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!