定義:定義一組算法,將每個算法都封裝起來,并且使它們之間可以互換
策略模式通用類圖:
Context 封裝角色:也叫上下文角色,起承上啟下封裝作用,屏蔽高層模塊對策略,算法的直接訪問,封裝可能存在的變化。
Strategy 抽象策略角色:抽象算法集合的接口,定義算法必須有的屬性與方法。
ConcreteStrategy 具體策略角色:實現抽象策略中的操作,該類含有具體的算法。
通用代碼演示:
抽象策略類:
public interface Strategy {
//策略模式的運算法則
public void doSomething();
}
具體策略類:
public class ConcreteStrategy1 implements Strategy {
@Override
public void doSomething() {
System.out.println("這是第一種算法");
}
}
public class ConcreteStrategy2 implements Strategy {
@Override
public void doSomething() {
System.out.println("這是第二種算法");
}
}
策略模式的重點在于封裝角色,它借鑒了代理模式的思路,但跟代理模式有區別:策略模式的封裝角色和被封裝的策略類不用是同一個接口,如果是同一個接口那就成為了代理模式。
封裝類:
public class Context {
//引入策略
private Strategy strategy = null;
//通過構造函數指定策略
public Context(Strategy strategy) {
this.strategy = strategy;
}
//調用策略的算法
public void doAnything(){
this.strategy.doSomething();
}
}
高層模塊:
public class Client {
public static void main(String[] args) {
//高層模塊聲明哪種策略
Strategy ConcreteStrategy1 = new ConcreteStrategy1();
Context context1 = new Context(ConcreteStrategy1);
context1.doAnything();
Strategy ConcreteStrategy2 = new ConcreteStrategy2();
Context context2 = new Context(ConcreteStrategy2);
context2.doAnything();
}
}
----------------output------------------
這是第一種算法
這是第二種算法
從代碼來看,策略模式采用了面向對象的繼承和多態機制。在具體策略類中實現多種具體的算法,然后由高層模塊自己帥選使用哪種算法。
策略模式優點
①算法可以自由切換:只要是在具體策略類中實現的算法,高層模塊都可以自由的切換使用算法。
②避免使用多重條件判斷:假如沒有策略模式,那么在切換算法時需要使用多重判斷條件,這樣下來代碼容易出錯。
③擴展性良好:理論上具體策略類中的算法可以無限擴展,只要系統允許。
策略模式的缺點
①由于具體策略類中所有算法對外公布,高層模塊在切換算法時,必須知道每個算法的區別,這樣會導致使用者分精力去了解不相關的事情,違反迪米特法則。在使用策略模式時,我們可以搭配工廠模式,代理模式等優化這個缺點。
②具體策略類數量多,每個類都是一個具體的算法,復用性低,難于管理。
策略模式的使用場景
①多個類只有某些行為上不同時
②算法需要自由切換的場景
③屏蔽算法規則,只需了解算法的作用與名字,外界傳遞參數,返回結果時
策略模式的注意事項
由策略模式的缺點,很容易碰到多個算法難于管理的問題。一般來講,當策略算法超過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;
}
};
public abstract int exec(int a,int b);
}
客戶端:
public class Client {
public static void main(String[] args) {
System.out.println(Calculator.ADD.exec(1,2));
System.out.println(Calculator.SUB.exec(1,2));
}
}
注意:由于枚舉類都是public,static,final的類型,因此在擴展性上受到了一定的約束,策略枚舉一般用在對象不經常改變的地方。
參考書籍:設計模式之禪 --- 秦小波 著