策略模式,你有多少個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é)果。
?