13-策略模式

策略模式

一、定義

定義一組算法,將每個算法搜封裝起來,並且使他們之間可以互換。

策略模式的通用類圖
在這裏插入圖片描述
Context是封裝角色,起承上啓下作用,屏蔽高層模塊對策略、算法的直接訪問,封裝可能存在的變化;Strategy是抽象策略角色,抽象策略算法,通常爲接口,定義每個策略或算法必須具有的方法和屬性;ConcreteStrategy是具體策略角色,實現抽象策略中的操作;

策略模式的通用源碼

  1. 抽象的策略角色

    public interface Strategy {
        //策略模式的運算法則
        public void doSomething();
    }
    
  2. 具體策略角色

    public class ConcreteStrategy1 implements Strategy {
        public void doSomething() {
        	System.out.println("具體策略1的運算法則");
        }
    }
    
    public class ConcreteStrategy2 implements Strategy {
         public void doSomething() {
            System.out.println("具體策略2的運算法則");
        }
    }
    
  3. 封裝角色

    public class Context {
        //抽象策略
        private Strategy strategy = null;
        
        //構造函數設置具體策略
        public Context(Strategy _strategy){
        	this.strategy = _strategy;
        }
        //封裝後的策略方法
        public void doAnythinig(){
        	this.strategy.doSomething();
        }
    }
    
  4. 高層模塊

    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的,擴展性受到了一定的約束,因此在系統開發中,策略枚舉一般擔當不經常發生變化的角色。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章