歡迎訪問我的主頁,最新的文章我會首先發布在個人主頁上:
策略模式,你有多少個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";
}
}
Ⅲ【覈查階段】———————————————————–
這個分析起來比較清晰了:
- 代碼職責分工明確,不同的業務變更修改不同的java類,便於開發與管理;
- 新增業務只需新增實現接口的實現類即可,同時在Excutor中進行分發;
Ⅳ【反思】———————————————————–
這時候我們來看看圖:
大家在這裏注意到,我將原本在LoginService中的if-else語句判斷挪到了LoadStrategyExcutor中,原本還有一種做法,就是將LoadStrategyExcutor中的switch-case挪回到LoginService中,直接讓LoginService來做判斷,這樣是否可以呢?
首先從功能上來說,當然沒有區別,系統會正常運轉。那區別在哪?主要是一個“職責劃分”問題,在面向對象編程裏面,重在一個解耦合與委派原則,希望能夠將“不屬於自己所管理”的部分不交給自己管理,
在這裏,可以發現LoginService充當的是client,其他幾個類完全輸入“策略模式”的內部成員。LoginService通過一個LoadStrategyExcutor.execute(user) 來調用整個“策略模式”模塊,這樣,策略模式模塊接收LoginService傳遞來的參數(正統一點說法是上下文Context),隔離到自己的區域處理業務邏輯,最終返回處理結果。