設計模式–策略模式

歡迎訪問我的主頁,最新的文章我會首先發布在個人主頁上:

http://blog.guaidm.com/shocky


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

策略模式,又是一個我幾乎在各個角落都有過使用的模式。因爲,他可以說把最常規的if-else給“面向對象化”了,封裝了算法。換句話說,當你有if-else的代碼塊的時候,理論上來說,都可以變成一個策略模式,當然,這只是打個誇張的比方,因爲設計模式的劣勢就在於相對複雜化代碼結構,思路結構化爲非過程化,所以只有值得優化爲的if-else塊使用策略模式才有價值。


〇 【業務場景】———————————

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

 

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

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

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

/**
 * 登錄業務邏輯處理類,這裏採用的struts2思路舉例
 * 這個LoginService相當於是受LoginAction的調用,所以返回String類型的返回頁標識
 *
 */
public class LoginService {

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


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


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

public class LoginService {

public String getPageByIdentity(User user){

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

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

/**
* 策略執行類,這裏對用的身份進行判斷,然後映射到不同的模式
*/
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() {
        //讀取數據庫等等操作,準備人事部門數據
        prepareDataForHR();
        //人事部門所獨有的業務處理
        hrOtherService();
        //返回成功頁面
        return "HR";
    }
}

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

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

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

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

  1. 代碼職責分工明確,不同的業務變更修改不同的java類,便於開發與管理;
  2. 新增業務只需新增實現接口的實現類即可,同時在Excutor中進行分發;

 

Ⅳ【反思】———————————————————–
這時候我們來看看圖:


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

首先從功能上來說,當然沒有區別,系統會正常運轉。那區別在哪?主要是一個“職責劃分”問題,在面向對象編程裏面,重在一個解耦合與委派原則,希望能夠將“不屬於自己所管理”的部分不交給自己管理,

在這裏,可以發現LoginService充當的是client,其他幾個類完全輸入“策略模式”的內部成員。LoginService通過一個LoadStrategyExcutor.execute(user) 來調用整個“策略模式”模塊,這樣,策略模式模塊接收LoginService傳遞來的參數(正統一點說法是上下文Context),隔離到自己的區域處理業務邏輯,最終返回處理結果。






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