設(shè)計(jì)模式之---策略模式

1.定義

策略模式定義了一系列算法,并將每一個(gè)算法封裝起來(lái),而且使他們還可以相互替換。策略模式讓算法獨(dú)立于使用它的客戶而獨(dú)立變化。

這種定義的語(yǔ)句總是有一種通病,喜歡把一個(gè)簡(jiǎn)單事物復(fù)雜化,這里舉個(gè)例子來(lái)說(shuō)明一下策略模式到底是用來(lái)干啥的。

比如我用代碼來(lái)解一道數(shù)學(xué)題,然后由于本人是一個(gè)天才,牛逼到不行的那種,我可以用N種解法來(lái)求解。每種解法都是一種解決方案,但每次使用時(shí),需要根據(jù)外在的約束條件來(lái)決定到底使用哪種算法來(lái)求解,原來(lái)的方法大概是來(lái)一個(gè)switch,搞很多case,來(lái)決定到底用哪個(gè)方案。這種方式一旦要修改就比較麻煩了,現(xiàn)在可以用策略模式來(lái)處理這種問(wèn)題了。


看圖說(shuō)話

附上UML圖一張:
圖片來(lái)源與網(wǎng)絡(luò)

策略模式

分析一下這個(gè)圖,在contect中有三種算法A,B,C可以解決,于是將這三種算法獨(dú)立出去成為單獨(dú)的類,他們有一個(gè)共同的父類,而Context類不需要與具體的算法類接觸。


還是看看代碼具體的實(shí)現(xiàn)

光看這個(gè)圖還是比較模糊的。

先看一下算法的父類:

//算法的抽象父類
public abstract class StrategyAbs {

    //每一個(gè)算法中都應(yīng)該有的方法
    abstract boolean DoWork();
}

所有的算法的具體實(shí)現(xiàn)不同,但是他們最終實(shí)現(xiàn)的功能或效果應(yīng)該是相同的,因此講道理是可以提取出一個(gè)或多個(gè)方法的。

然后是算法的具體實(shí)現(xiàn):

//算法
public class AStrategy extends StrategyAbs {
    private static final String TAG = "Strategy";

    @Override
    void DoWork() {
        Log.d(TAG, "DoWork: i am A,i am working now");
    }
}

這里假設(shè)有A,B,C三種算法,都是一樣的,這里只列出A的代碼。

StrategyUtil:

class StrategyUtil {
    private StrategyAbs strategyAbs;

    //調(diào)用者在這里傳進(jìn)來(lái)的就是調(diào)用者想要使用的A,還是B還是C
    //傳進(jìn)來(lái)的都是StrategyAbs的子類,所以用StrategyAbs可以統(tǒng)一接收
    public void setStrategyType(StrategyAbs strategyType) {
        strategyAbs = strategyType;
    }

    //調(diào)用父類的方法,而父類的方法是抽象的,所以會(huì)自動(dòng)執(zhí)行相應(yīng)子類的方法
    public void work() {
        strategyAbs.DoWork();
    }
}

調(diào)用者只會(huì)和這個(gè)類接觸,調(diào)用者因此不用關(guān)心具體算法類是怎么實(shí)現(xiàn)的。

最后看到底怎么去調(diào)用:

xml布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="st.zlei.com.strategypattern.MainActivity"
    android:orientation="vertical">

    <Button
        android:id="@+id/a_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="do work By A!"
         />

    <Button
        android:id="@+id/b_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="do work By B!"
        />
    <Button
        android:id="@+id/c_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="do work By C!"
        />

    <Button
        android:id="@+id/overAll_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="do work By C!"
        />
</LinearLayout>

xml布局很簡(jiǎn)單,就長(zhǎng)這樣:

xml布局

實(shí)現(xiàn)的功能是點(diǎn)擊不同的Button,就采用不同的策略。

調(diào)用者:

       a_button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //獲取對(duì)象
                StrategyUtil strategyUtil = new StrategyUtil();
                //通過(guò)setStrategyType注入想要采用策略類型
                strategyUtil.setStrategyType(new AStrategy());
                //調(diào)用策略的方法
                strategyUtil.work();
            }
        });

        b_button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                StrategyUtil strategyUtil = new StrategyUtil();
                strategyUtil.setStrategyType(new BStrategy());
                strategyUtil.work();
            }
        });

        c_button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                StrategyUtil strategyUtil = new StrategyUtil();
                strategyUtil.setStrategyType(new CStrategy());
                strategyUtil.work();
            }
        });

最后看一下打印結(jié)果:

打印結(jié)果

可以看到點(diǎn)擊A按鈕,策略A就開(kāi)始working,點(diǎn)擊B按鈕,策略B開(kāi)始working,點(diǎn)擊C按鈕,策略C開(kāi)始working。

還有一點(diǎn)就是這種寫(xiě)法還可以自定義一種策略:

        a_button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //獲取對(duì)象
                StrategyUtil strategyUtil = new StrategyUtil();
                //通過(guò)setStrategyType注入想要采用策略類型
                //當(dāng)在這里不傳子類策略的對(duì)象,而是直接new 一個(gè)父類的抽象類,就必須要重寫(xiě)DoWork方法,已達(dá)到自定義的功能
                strategyUtil.setStrategyType(new StrategyAbs() {
                    @Override
                    boolean DoWork() {
                        return false;
                    }
                });
                //調(diào)用策略的方法
                strategyUtil.work();
            }
        });

番外:

現(xiàn)在假設(shè)有一種需求,我希望優(yōu)先使用A策略,其次使用B策略,當(dāng)A,B策略都無(wú)法工作時(shí),才采用C策略。

這時(shí)候xml代碼多加一個(gè)button了,像這樣:

    <Button
        android:id="@+id/overAll_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="do work First By A then B then C"
        />

修改一下A,B,C策略的方法:

public class AStrategy extends StrategyAbs {
    private static final String TAG = "Strategy";

    //當(dāng)返回true的時(shí)候,表示A策略可以正常工作,false表示A策略無(wú)法工作
    @Override
    boolean DoWork() {
        Random random = new Random();
        boolean b = random.nextBoolean();
        if (b){
            Log.d(TAG, "DoWork: i am A,i am working now");
        }else {
            Log.d(TAG, "DoWork: i am A,i am busying");
        }
        return b;
    }
}

public class BStrategy extends StrategyAbs {
    private static final String TAG = "Strategy";
    //當(dāng)返回true的時(shí)候,表示B策略可以正常工作,false表示B策略無(wú)法工作
    @Override
    boolean DoWork() {
        Random random = new Random();
        boolean b = random.nextBoolean();
        if (b){
            Log.d(TAG, "DoWork: i am B,i am working now");
        }else {
            Log.d(TAG, "DoWork: i am B,i am busying");
        }
        return b;
    }
}

public class CStrategy extends StrategyAbs {
    private static final String TAG = "Strategy";

    @Override
    boolean DoWork() {
        //c策略作為A,B,的備用策略,它必須要保證自己是可用的。
        Log.d(TAG, "DoWork: i am C,i am working now");

        return true;
    }
}

添加一個(gè)策略
使用這個(gè)策略就可以按照需求順序使用A,B,C策略

class OverALlStrategy extends StrategyAbs {
    AStrategy aStrategy = new AStrategy();
    BStrategy bStrategy = new BStrategy();
    CStrategy cStrategy = new CStrategy();
    @Override
    boolean DoWork() {
        if (!aStrategy.DoWork()) {
            if (!bStrategy.DoWork()) {
                cStrategy.DoWork();
            }
        }
        return false;
    }
}

調(diào)用者:

        overAll_button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                StrategyUtil strategyUtil = new StrategyUtil();
                strategyUtil.setStrategyType(new OverALlStrategy());
                strategyUtil.work();
            }
        });

再看一下打印結(jié)果:


A可以工作
A不可以工作,B可以工作
AB都不可以工作,C可以工作

滿足了優(yōu)先使用A策略,再使用B策略,最后使用C策略的要求。


總結(jié)

到這里策略模式就講完了,這種模式的可擴(kuò)展性,可維護(hù)性更好,核心內(nèi)容就在于setStrategyType這個(gè)方法,傳入的是具體的策略子類,但是用抽象父類的引用去接收,接收的始終不變,可是傳入的可以改變成不同的策略。因此要求所有子類的功能實(shí)現(xiàn)的方法是統(tǒng)一的,以便被抽象到父類中去。舉個(gè)例子比如A,B,C策略的功能實(shí)現(xiàn)的方法都叫叫DoWork,父類才可以有抽象的方法DoWork,然后根據(jù)setStrategyType傳入的具體策略的類型,會(huì)自動(dòng)調(diào)用相應(yīng)子類的DoWork方法,如果A策略的功能方法叫methodA,B策略的功能方法叫methodB,C策略的功能方法叫methodC。那么父類是無(wú)法調(diào)用的,因?yàn)楦割愂菬o(wú)法知道該調(diào)用哪個(gè)的。

這文使用的代碼可以在本人github上找到-->傳送門(mén)

最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,506評(píng)論 19 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 34,626評(píng)論 18 399
  • 工廠模式類似于現(xiàn)實(shí)生活中的工廠可以產(chǎn)生大量相似的商品,去做同樣的事情,實(shí)現(xiàn)同樣的效果;這時(shí)候需要使用工廠模式。簡(jiǎn)單...
    舟漁行舟閱讀 8,110評(píng)論 2 17
  • 中國(guó)首屆新微商暨網(wǎng)紅頒獎(jiǎng)盛典-傲華薈,在最具微商代表的城市——廣州,完美的落下帷幕,本次大會(huì)超人氣圓滿成功!傲華薈...
    中道文化閱讀 750評(píng)論 0 0
  • 有人問(wèn),大學(xué)室友對(duì)自己的成長(zhǎng)影響大嗎?我說(shuō),影響簡(jiǎn)直不要太大。 大學(xué)四年,大部分人接觸最多的還是室友。關(guān)上門(mén)男生一...
    太陽(yáng)的森林閱讀 591評(píng)論 0 3

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