策略模式
一、定義
定義一組算法,將每個算法搜封裝起來,並且使他們之間可以互換。
策略模式的通用類圖
Context是封裝角色,起承上啓下作用,屏蔽高層模塊對策略、算法的直接訪問,封裝可能存在的變化;Strategy是抽象策略角色,抽象策略算法,通常爲接口,定義每個策略或算法必須具有的方法和屬性;ConcreteStrategy是具體策略角色,實現抽象策略中的操作;
策略模式的通用源碼
-
抽象的策略角色
public interface Strategy { //策略模式的運算法則 public void doSomething(); }
-
具體策略角色
public class ConcreteStrategy1 implements Strategy { public void doSomething() { System.out.println("具體策略1的運算法則"); } }
public class ConcreteStrategy2 implements Strategy { public void doSomething() { System.out.println("具體策略2的運算法則"); } }
-
封裝角色
public class Context { //抽象策略 private Strategy strategy = null; //構造函數設置具體策略 public Context(Strategy _strategy){ this.strategy = _strategy; } //封裝後的策略方法 public void doAnythinig(){ this.strategy.doSomething(); } }
-
高層模塊
public class Client { public static void main(String[] args) { //聲明一個具體的策略 Strategy strategy = new ConcreteStrategy1(); //聲明上下文對象 Context context = new Context(strategy); //執行封裝後的方法 context.doAnythinig(); } }
二、策略模式的優點
-
算法可以自由切換
只要實現抽象策略,它就成爲策略家族的一個成員,通過封裝角色對其進行封裝,保證對外提供“可自由切換”的策略
-
避免使用多重條件判斷
使用策略模式後,可以由其他模塊決定採用何種策略,策略家族對外提供的訪問接口就是封裝類,簡化了操作,同時避免了條件語句判斷
-
擴展性良好
在現有的系統中增加一個策略,只要實現接口就可以了,其他都不用修改,類似於一個可反覆拆卸的插件,符合了OCP原則。
三、策略模式的缺點
-
策略類數量增多
每個策略都要建立一個類,複用的可能性小,類數量增多
-
所有的策略類搜需要對外暴露
上層模塊必須知道有哪些策略,然後才能決定使用哪一個策略,與迪米特法則是相違背的
四、策略模式的使用場景
- 多個類只有在算法或行爲上稍有不同的場景
- 算法需要自由切換的場景
- 需要屏蔽算法規則的場景
注意:如果系統中的一個策略家族的具體策略數量超過4個,則需要考慮使用混合模式,解決
策略類膨脹和對外暴露的問題,否則日後的系統維護困難。
擴展:策略枚舉
原有定義在抽象策略中的方法移植到枚舉中,每個枚舉成員就成爲一個具體策略。
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;
}
};
String value = "";
//定義成員值類型
private Calculator(String _value){
this.value = _value;
}
//獲得枚舉成員的值
public String getValue(){
return this.value;
}
//聲明一個抽象函數
public abstract int exec(int a,int b);
}
public class Client {
public static void main(String[] args) {
//輸入的兩個參數是數字
int a = Integer.parseInt(args[0]);
String symbol = args[1]; //符號
int b = Integer.parseInt(args[2]);
System.out.println("輸入的參數爲:"+Arrays.toString(args));
if("+".equest(symbol){
System.out.println("運行結果爲:"+a+symbol+b+"="+Calculator.ADD.exec(a,b));
}else{
System.out.println("運行結果爲:"+a+symbol+b+"="+Calculator.SUB.exec(a,b));
}
}
注意 策略枚舉是一個非常優秀和方便的模式,但是它受枚舉類型的限制,每個枚舉項都是public、final、static的,擴展性受到了一定的約束,因此在系統開發中,策略枚舉一般擔當不經常發生變化的角色。