設計模式-策略模式

策略模式,你有多少個if-else,就有可以寫多少個策略模式——只要他值得

策略模式,又是一個我?guī)缀踉诟鱾€角落都有過使用的模式。因為,他可以說把最常規(guī)的if-else給“面向?qū)ο蠡绷耍庋b了算法。換句話說,當你有if-else的代碼塊的時候,理論上來說,都可以變成一個策略模式,當然,這只是打個夸張的比方,因為設計模式的劣勢就在于相對復雜化代碼結(jié)構(gòu),思路結(jié)構(gòu)化為非過程化,所以只有值得優(yōu)化為的if-else塊使用策略模式才有價值

〇 【業(yè)務場景】———————————

手頭有一個管理系統(tǒng),其中有三種權(quán)限,分別為ABC,當A登錄后,顯示員工信息;當B登錄后,顯示庫存信息;當C登錄后,顯示財務信息。目前系統(tǒng)只有三個身份,以后走同樣一個入口進去的身份會更多。

?

Ⅰ 【分析階段】———————————

A來就這樣,B進來就那樣,C進來就這樣那樣.. 這個如果第一時間想到在登錄業(yè)務那里進行if-else判斷,那么恭喜你,距離策略模式很近了!怎么了,沒這么簡單?就是這么簡單!這回我先放代碼了

如果是if-else會是怎么樣呢?


/**
 * 登錄業(yè)務邏輯處理類,這里采用的struts2思路舉例
 * 這個LoginService相當于是受LoginAction的調(diào)用,所以返回String類型的返回頁標識
 *
 */
public class LoginService {

    /**
     * Action中就會調(diào)用這個方法
     * @param user
     * @return
     */
    public String getPageByIdentity(User user){
        
        //一些其他的操作
        doSth();
        
        //要根據(jù)用戶身份獲取對應的響應頁面
        if(user.getIdentity()==1){
            
            //讀取數(shù)據(jù)庫等等操作,準備人事部門數(shù)據(jù)
            prepareDataForHR();
            //人事部門所獨有的業(yè)務處理
            hrOtherService();
            //返回成功頁面
            return "HR";
        }else if(user.getIdentity()==2){
            //讀取數(shù)據(jù)庫等等操作,準備銷售部門數(shù)據(jù)
            prepareDataForSale();
            //銷售部門所獨有的業(yè)務處理
            saleOtherService();
            //返回成功頁面
            return "SALE";
        }else if(user.getIdentity()==3){
            //讀取數(shù)據(jù)庫等等操作,準備財務部門數(shù)據(jù)
            prepareDataForFinace();
            //財務部門所獨有的業(yè)務處理
            finaceOtherService();
            //返回成功頁面
            return "FINACE";
        }else{
            return "ERROR";
        }
    }
}

這樣思路沒問題,但是很明顯:代碼冗雜,一旦擴展新的權(quán)限,或者復雜化現(xiàn)有的業(yè)務,將會反復變動這段代碼。所以,換用策略模式:

?

Ⅱ【設計階段】——————————————————-


public class LoginService {

public String getPageByIdentity(User user){

        //一些其他的操作
        doSth();

        //這里開始將if-else邏輯判斷委派給策略模式的執(zhí)行器
        return LoadStrategyExcutor.execute(user);
    }
}

/**
* 策略執(zhí)行類,這里對用的身份進行判斷,然后映射到不同的模式
*/
public class LoadStrategyExcutor {

    public static String execute(User user){

        IdentityLoadService loadStrategy = null;

        switch(user.getIdentityCode()){
            case 1 : loadStrategy = new UserALoadService();
                break;
            case 2 : loadStrategy = new UserBLoadService();
                break;
            case 3 : loadStrategy = new UserCLoadService();
                break;
            default: break;
        }

    return loadStrategy.doService();
    }
}

public class UserALoadService implements IdentityLoadService {
    @Override
    public String doService() {
        //讀取數(shù)據(jù)庫等等操作,準備人事部門數(shù)據(jù)
        prepareDataForHR();
        //人事部門所獨有的業(yè)務處理
        hrOtherService();
        //返回成功頁面
        return "HR";
    }
}

public class UserBLoadService implements IdentityLoadService {
    @Override
    public String doService() {
        //讀取數(shù)據(jù)庫等等操作,準備銷售部門數(shù)據(jù)
        prepareDataForSale();
        //銷售部門所獨有的業(yè)務處理
        saleOtherService();
        //返回成功頁面
        return "SALE";
    }
}

public class UserCLoadService implements IdentityLoadService {
    @Override
    public String doService() {
        //讀取數(shù)據(jù)庫等等操作,準備財務部門數(shù)據(jù)
        prepareDataForFinace();
        //財務部門所獨有的業(yè)務處理
        finaceOtherService();
        //返回成功頁面
        return "FINACE";
    }
}

Ⅲ【核查階段】———————————————————–

這個分析起來比較清晰了:

代碼職責分工明確,不同的業(yè)務變更修改不同的java類,便于開發(fā)與管理;

新增業(yè)務只需新增實現(xiàn)接口的實現(xiàn)類即可,同時在Excutor中進行分發(fā);

?

Ⅳ【反思】———————————————————–

這時候我們來看看圖:



大家在這里注意到,我將原本在LoginService中的if-else語句判斷挪到了LoadStrategyExcutor中,原本還有一種做法,就是將LoadStrategyExcutor中的switch-case挪回到LoginService中,直接讓LoginService來做判斷,這樣是否可以呢?


public class LoginService {

    public String getPageByIdentity(User user){
        
        doSth();
        IdentityLoadService loadStrategy = null;
        switch(user.getIdentityCode()){
            case 1 : loadStrategy = new UserALoadService();
                     break;
            case 2 : loadStrategy = new UserBLoadService();
                    break;
            case 3 : loadStrategy = new UserCLoadService();
                    break;
            default: break;
        }
        
        return loadStrategy.doService();
    }
}

首先從功能上來說,當然沒有區(qū)別,系統(tǒng)會正常運轉(zhuǎn)。那區(qū)別在哪?主要是一個“職責劃分”問題,在面向?qū)ο缶幊汤锩妫卦谝粋€解耦合與委派原則,希望能夠?qū)ⅰ安粚儆谧约核芾怼钡牟糠植唤唤o自己管理.

在這里,可以發(fā)現(xiàn)LoginService充當?shù)氖莄lient,其他幾個類完全輸入“策略模式”的內(nèi)部成員。LoginService通過一個LoadStrategyExcutor.execute(user)?來調(diào)用整個“策略模式模塊",這樣,策略模式模塊接收LoginService傳遞來的參數(shù)(正統(tǒng)一點說法是上下文Context),隔離到自己的區(qū)域處理業(yè)務邏輯,最終返回處理結(jié)果。

?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容

  • 目錄 本文的結(jié)構(gòu)如下: 引言 什么是策略模式 模式的結(jié)構(gòu) 典型代碼 代碼示例 策略模式和模板方法模式的區(qū)別 優(yōu)點和...
    w1992wishes閱讀 898評論 1 7
  • 概念及定義 概念在完成某一功能時,有時需要根據(jù)不同環(huán)境采取不同的策略或行為。將這些不同的策略或行為(稱為算法)一一...
    maxwellyue閱讀 573評論 0 0
  • 工廠模式類似于現(xiàn)實生活中的工廠可以產(chǎn)生大量相似的商品,去做同樣的事情,實現(xiàn)同樣的效果;這時候需要使用工廠模式。簡單...
    舟漁行舟閱讀 7,842評論 2 17
  • 愛情 它隱帶著電流 同頻的人相撞了 火花四濺 不同頻的人 寂靜無聲
    雪莉詩話閱讀 376評論 3 21