設(shè)計(jì)模式之——策略模式(Strategy Pattern)及在Android中的應(yīng)用

相信大家都用過計(jì)算器,輸入一個(gè)數(shù),然后輸入運(yùn)算符,然后再輸入一個(gè)數(shù),就會(huì)根據(jù)不同的運(yùn)算符做不同的運(yùn)算。

最直接的加減法:

public class Calculator {
    //加符號(hào)
    private final static String ADD_SYMBOL = "+";
    //減符號(hào)
    private final static String SUB_SYMBOL = "-";
    public int exec(int a,int b,String symbol){
        int result =0;
        if(symbol.equals(ADD_SYMBOL)){
            result = this.add(a, b);
        }else if(symbol.equals(SUB_SYMBOL)){
            result = this.sub(a, b);
        }
        return result;
    }
    //加法運(yùn)算
    private int add(int a,int b){
        return a+b;
    }
    //減法運(yùn)算
    private int sub(int a,int b){
        return a-b;
    }
}

用戶使用:

public class Client {
    public static void main(String[] args) {
        //輸入的兩個(gè)參數(shù)是數(shù)字
        int a = Integer.parseInt(args[0]);
        String symbol = args[1]; //符號(hào)
        int b = Integer.parseInt(args[2]);
        System.out.println("輸入的參數(shù)為:"+Arrays.toString(args));
        //生成一個(gè)運(yùn)算器
        Calculator cal = new Calculator();
        System.out.println("運(yùn)行結(jié)果為:"+a + symbol + b + "=" + cal.exec(a, b, symbol));
    }
}

這是最簡(jiǎn)單直接的代碼,有什么問題嗎?假如用戶需要這個(gè)計(jì)算器支持乘法呢?就要改Calculator類,明顯違背了開閉原則,系統(tǒng)也不利于維護(hù)。

那么怎么設(shè)計(jì)成可以擴(kuò)展的代碼呢?就需要策略模式了。

策略模式類圖

定義:策略模式也叫政策模式,定義一組算法,將每個(gè)算法都封裝起來,并且使它們之間可以互換。

這個(gè)定義是非常明確、清晰的,“定義一組算法”,看看加減法和乘法是不是三個(gè)算
法?“將每個(gè)算法都封裝起來”,那么我們定義一個(gè)類,封裝算法,可以互換,是不是多態(tài)的特征呢?我們用代碼把這個(gè)定義實(shí)現(xiàn)下:

//抽象策略
interface Calculator {
    public int exec(int a,int b);
}
// 具體策略

public class Add implements Calculator {
    // 加法運(yùn)算
    public int exec(int a, int b) {
        return a+b;
    }
}
public class Sub implements Calculator {
    //減法運(yùn)算
    public int exec(int a, int b) {
        return a-b;
    }
}

策略定義好了,然后定義一個(gè)Context封裝類,其作用是承裝三個(gè)策略,根據(jù)不同的需要替換:

public class Context {
    private Calculator cal = null;
    public Context(Calculator _cal){
        this.cal = _cal;
    }
    public int exec(int a,int b,String symbol){
        return this.cal.exec(a, b);
    }
}

用戶使用:

public class Client {
    //加符號(hào)
    public final static String ADD_SYMBOL = "+";
    //減符號(hào)
    public final static String SUB_SYMBOL = "-";
    public static void main(String[] args) {
        //輸入的兩個(gè)參數(shù)是數(shù)字
        int a = Integer.parseInt(args[0]);
        String symbol = args[1]; //符號(hào)
        int b = Integer.parseInt(args[2]);
        System.out.println("輸入的參數(shù)為:"+Arrays.toString(args));
        //上下文
        Context context = null;
        //判斷初始化哪一個(gè)策略
        if(symbol.equals(ADD_SYMBOL)){
            context = new Context(new Add());
        }else if(symbol.equals(SUB_SYMBOL)){
            context = new Context(new Sub());
        }
        System.out.println("運(yùn)行結(jié)果為:"+a+symbol+b+"="+context.exec(a,b,symbol));
    }
}

需要增加乘法呢?實(shí)現(xiàn)Calculator ,增加乘法算法,直接替換就ok了:

public class Mul implements Calculator {
    //乘法運(yùn)算
    public int exec(int a, int b) {
        return a*b;
    }
}

public class Client {
    //加符號(hào)
    public final static String ADD_SYMBOL = "+";
    //減符號(hào)
    public final static String SUB_SYMBOL = "-";
    //乘符號(hào)
    public final static String MUL_SYMBOL = "*";
    public static void main(String[] args) {
        //輸入的兩個(gè)參數(shù)是數(shù)字
        int a = Integer.parseInt(args[0]);
        String symbol = args[1]; //符號(hào)
        int b = Integer.parseInt(args[2]);
        System.out.println("輸入的參數(shù)為:"+Arrays.toString(args));
        //上下文
        Context context = null;
        //判斷初始化哪一個(gè)策略
        if(symbol.equals(ADD_SYMBOL)){
            context = new Context(new Add());
        }else if(symbol.equals(SUB_SYMBOL)){
            context = new Context(new Sub());
        }else if(symbol.equals(MUL_SYMBO)){
            context = new Context(new Mul());
        }
        System.out.println("運(yùn)行結(jié)果為:"+a+symbol+b+"="+context.exec(a,b,symbol));
    }
}

我們總結(jié)下這樣的寫的優(yōu)點(diǎn):

  • 算法可以自由切換
    這是策略模式本身定義的,只要實(shí)現(xiàn)抽象策略,它就成為策略家族的一個(gè)成員,通過封
    裝角色對(duì)其進(jìn)行封裝,保證對(duì)外提供“可自由切換”的策略。
  • 避免使用多重條件判斷
    如果沒有策略模式,我們想想看會(huì)是什么樣子?一個(gè)策略家族有5個(gè)策略算法,一會(huì)要
    使用A策略,一會(huì)要使用B策略,怎么設(shè)計(jì)呢?使用多重的條件語句?多重條件語句不易維
    護(hù),而且出錯(cuò)的概率大大增強(qiáng)。使用策略模式后,可以由其他模塊決定采用何種策略,策略
    家族對(duì)外提供的訪問接口就是封裝類,簡(jiǎn)化了操作,同時(shí)避免了條件語句判斷。
  • 擴(kuò)展性良好
    這甚至都不用說是它的優(yōu)點(diǎn),因?yàn)樗黠@了。在現(xiàn)有的系統(tǒng)中增加一個(gè)策略太容易
    了,只要實(shí)現(xiàn)接口就可以了,其他都不用修改,類似于一個(gè)可反復(fù)拆卸的插件,這大大地符合了OCP原則。

當(dāng)然他也不可避免的具有缺點(diǎn):

  • 策略類數(shù)量增多
    每一個(gè)策略都是一個(gè)類,復(fù)用的可能性很小,類數(shù)量增多。
  • 所有的策略類都需要對(duì)外暴露
    上層模塊必須知道有哪些策略,然后才能決定使用哪一個(gè)策略,這與迪米特法則是相違
    背的,我只是想使用了一個(gè)策略,我憑什么就要了解這個(gè)策略呢?那要你的封裝類還有什么
    意義?這是原裝策略模式的一個(gè)缺點(diǎn),幸運(yùn)的是,我們可以使用其他模式來修正這個(gè)缺陷,
    如工廠方法模式、代理模式或享元模式。

那我們什么應(yīng)該使用策略模式呢:

  • 多個(gè)類只有在算法或行為上稍有不同的場(chǎng)景。
  • 算法需要自由切換的場(chǎng)景。
    例如,算法的選擇是由使用者決定的,或者算法始終在進(jìn)化,特別是一些站在技術(shù)前沿
    的行業(yè),連業(yè)務(wù)專家都無法給你保證這樣的系統(tǒng)規(guī)則能夠存在多長(zhǎng)時(shí)間,在這種情況下策略
    模式是你最好的助手。
  • 需要屏蔽算法規(guī)則的場(chǎng)景。
    現(xiàn)在的科技發(fā)展得很快,人腦的記憶是有限的(就目前來說是有限的),太多的算法你
    只要知道一個(gè)名字就可以了,傳遞相關(guān)的數(shù)字進(jìn)來,反饋一個(gè)運(yùn)算結(jié)果,萬事大吉。

Android中有一個(gè)需求場(chǎng)景是不是特別像?有數(shù)據(jù)的時(shí)候,要展示數(shù)據(jù);無網(wǎng)絡(luò)的時(shí)候,展示重試界面。對(duì)的,就是狀態(tài)策略,根據(jù)不同的狀態(tài)選取不同的策略,但是我們一般不單獨(dú)使用策略模式,而是使用工廠方法來實(shí)現(xiàn)策略類的聲明。也就是利用混編,揚(yáng)長(zhǎng)避短,達(dá)到最優(yōu)的設(shè)計(jì)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 【學(xué)習(xí)難度:★☆☆☆☆,使用頻率:★★★★☆】直接出處:策略模式梳理和學(xué)習(xí):https://github.com/...
    BruceOuyang閱讀 1,635評(píng)論 3 5
  • 工廠模式類似于現(xiàn)實(shí)生活中的工廠可以產(chǎn)生大量相似的商品,去做同樣的事情,實(shí)現(xiàn)同樣的效果;這時(shí)候需要使用工廠模式。簡(jiǎn)單...
    舟漁行舟閱讀 8,131評(píng)論 2 17
  • javascript設(shè)計(jì)模式與開發(fā)實(shí)踐 設(shè)計(jì)模式 每個(gè)設(shè)計(jì)模式我們需要從三點(diǎn)問題入手: 定義 作用 用法與實(shí)現(xiàn) 單...
    穿牛仔褲的蚊子閱讀 4,494評(píng)論 0 13
  • 1.初識(shí)策略模式 定義一系列的算法,把它們一個(gè)個(gè)封裝起來,并且使它們可相互替換。本模式使得算法可獨(dú)立于使用它的客戶...
    王偵閱讀 1,545評(píng)論 0 3
  • 今天休息。這是把清明小長(zhǎng)假提前休了一天。也好,分散休息,不至于一下子歇得無聊。 原本打算出去踏踏青,感受一下春光。...
    陽覓閱讀 188評(píng)論 0 2

友情鏈接更多精彩內(nèi)容