需求
最近寫了一個服務:根據優惠券的類型resourceType和編碼resourceId來 查詢 發放方式grantType和領取規則
實現方式:
根據優惠券類型resourceType -> 確定查詢哪個數據表
根據編碼resourceId -> 到對應的數據表里邊查詢優惠券的派發方式grantType和領取規則
優惠券有多種類型,分別對應了不同的數據庫表:
紅包 —— 紅包發放規則表
購物券 —— 購物券表
QQ會員
外賣會員
實際的優惠券遠不止這些,這個需求是要我們寫一個業務分派的邏輯
第一個能想到的思路就是if-else或者switch case:
switch(resourceType){
case"紅包":
查詢紅包的派發方式
break;
case"購物券":
查詢購物券的派發方式
break;
case"QQ會員":
break;
case"外賣會員":
break;
......
default:logger.info("查找不到該優惠券類型resourceType以及對應的派發方式");
break;
}
如果要這么寫的話, 一個方法的代碼可就太長了,影響了可讀性。(別看著上面case里面只有一句話,但實際情況是有很多行的)
而且由于 整個 if-else的代碼有很多行,也不方便修改,可維護性低。
策略模式
策略模式是把 if語句里面的邏輯抽出來寫成一個類,如果要修改某個邏輯的話,僅修改一個具體的實現類的邏輯即可,可維護性會好不少。
以下是策略模式的具體結構

策略模式在業務邏輯分派的時候還是if-else,只是說比第一種思路的if-else 更好維護一點。
switch(resourceType){
case"紅包":
StringgrantType=newContext(newRedPaper()).ContextInterface();
break;
case"購物券":
StringgrantType=newContext(newShopping()).ContextInterface();
break;
......
default:logger.info("查找不到該優惠券類型resourceType以及對應的派發方式");
break;
但缺點也明顯:
如果 if-else的判斷情況很多,那么對應的具體策略實現類也會很多,上邊的具體的策略實現類還只是2個,查詢紅包發放方式寫在類RedPaper里邊,購物券寫在另一個類Shopping里邊;那資源類型多個QQ會員和外賣會員,不就得再多寫兩個類?有點麻煩了
沒法俯視整個分派的業務邏輯
Map+函數式接口
用上了Java8的新特性lambda表達式
判斷條件放在key中
對應的業務邏輯放在value中
這樣子寫的好處是非常直觀,能直接看到判斷條件對應的業務邏輯
需求:根據優惠券(資源)類型resourceType和編碼resourceId查詢派發方式grantType
上代碼:
@Service
publicclassQueryGrantTypeService{
@Autowired
privateGrantTypeSerivegrantTypeSerive;
privateMap>grantTypeMap=newHashMap<>();
/**
*初始化業務分派邏輯,代替了if-else部分
*key:優惠券類型
*value:lambda表達式,最終會獲得該優惠券的發放方式
*/
@PostConstruct
publicvoiddispatcherInit(){
grantTypeMap.put("紅包",resourceId->grantTypeSerive.redPaper(resourceId));
grantTypeMap.put("購物券",resourceId->grantTypeSerive.shopping(resourceId));
grantTypeMap.put("qq會員",resourceId->grantTypeSerive.QQVip(resourceId));
}
publicStringgetResult(StringresourceType){
//Controller根據優惠券類型resourceType、編碼resourceId去查詢發放方式grantType
Functionresult=getGrantTypeMap.get(resourceType);
if(result!=null){
//傳入resourceId執行這段表達式獲得String型的grantType
returnresult.apply(resourceId);
}
return"查詢不到該優惠券的發放方式";
}
}
如果單個 if 語句塊的業務邏輯有很多行的話,我們可以把這些 業務操作抽出來,寫成一個單獨的Service,即:
//具體的邏輯操作
@Service
publicclassGrantTypeSerive{
publicStringredPaper(StringresourceId){
//紅包的發放方式
return"每周末9點發放";
}
publicStringshopping(StringresourceId){
//購物券的發放方式
return"每周三9點發放";
}
publicStringQQVip(StringresourceId){
//qq會員的發放方式
return"每周一0點開始秒殺";
}
}
入參String resourceId是用來查數據庫的,這里簡化了,傳參之后不做處理。
用http調用的結果:
@RestController
publicclassGrantTypeController{
@Autowired
privateQueryGrantTypeServicequeryGrantTypeService;
@PostMapping("/grantType")
publicStringtest(StringresourceName){
returnqueryGrantTypeService.getResult(resourceName);
}
}

用Map+函數式接口也有弊端:
你的隊友得會lambda表達式才行啊,他不會讓他自己百度去
最后捋一捋本文講了什么
策略模式通過接口、實現類、邏輯分派來完成,把 if語句塊的邏輯抽出來寫成一個類,更好維護。
Map+函數式接口通過Map.get(key)來代替 if-else的業務分派,能夠避免策略模式帶來的類增多、難以俯視整個業務邏輯的問題。
審核編輯:劉清
-
編碼器
+關注
關注
45文章
3953瀏覽量
142621 -
數據庫
+關注
關注
7文章
4019瀏覽量
68339
原文標題:Map+函數式接口,“更完美” 的解決 if-else的問題
文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
煉獄傳奇-if_else與case之戰
FPGA學習系列:if-else與case
從入門到高級替換If-Else的5種方法示例
不會有人不知道怎么優雅的替換if-else語句吧
像Arduino里的MAP函數,應用在STM32單片機上。
什么是SystemVerilog-決策語句-if-else語句?
如何通過策略模式簡化if-else
什么是函數式接口
Map+函數式接口如何完美的解決if-else問題?
評論