來源:https://blog.csdn.net/qq_44384533/article/details/109197926
本文介紹策略模式的具體應用以及Map+函式式介面如何 “更完美” 的解決 if-else的問題,
文章目錄
- 需求
- 策略模式
- Map+函式式介面
- 最后捋一捋本文講了什么
需求
最近寫了一個服務:根據優惠券的型別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 "紅包":
String grantType=new Context(new RedPaper()).ContextInterface();
break;
case "購物券":
String grantType=new Context(new Shopping()).ContextInterface();
break;
......
default : logger.info("查找不到該優惠券型別resourceType以及對應的派發方式");
break;
但缺點也明顯:
- 如果 if-else的判斷情況很多,那么對應的具體策略實作類也會很多,上邊的具體的策略實作類還只是2個,查詢紅包發放方式寫在類RedPaper里邊,購物券寫在另一個類Shopping里邊;那資源型別多個QQ會員和外賣會員,不就得再多寫兩個類?有點麻煩了
- 沒法俯視整個分派的業務邏輯
Map+函式式介面
用上了Java8的新特性lambda運算式
- 判斷條件放在key中
- 對應的業務邏輯放在value中
這樣子寫的好處是非常直觀,能直接看到判斷條件對應的業務邏輯
需求:根據優惠券(資源)型別resourceType和編碼resourceId查詢派發方式grantType
上代碼:
@Service
public class QueryGrantTypeService {
@Autowired
private GrantTypeSerive grantTypeSerive;
private Map<String, Function<String,String>> grantTypeMap=new HashMap<>();
/**
* 初始化業務分派邏輯,代替了if-else部分
* key: 優惠券型別
* value: lambda運算式,最侄訓獲得該優惠券的發放方式
*/
@PostConstruct
public void dispatcherInit(){
grantTypeMap.put("紅包",resourceId->grantTypeSerive.redPaper(resourceId));
grantTypeMap.put("購物券",resourceId->grantTypeSerive.shopping(resourceId));
grantTypeMap.put("qq會員",resourceId->grantTypeSerive.QQVip(resourceId));
}
public String getResult(String resourceType){
//Controller根據 優惠券型別resourceType、編碼resourceId 去查詢 發放方式grantType
Function<String,String> result=getGrantTypeMap.get(resourceType);
if(result!=null){
//傳入resourceId 執行這段運算式獲得String型的grantType
return result.apply(resourceId);
}
return "查詢不到該優惠券的發放方式";
}
}
如果單個 if 陳述句塊的業務邏輯有很多行的話,我們可以把這些 業務操作抽出來,寫成一個單獨的Service,即:
//具體的邏輯操作
@Service
public class GrantTypeSerive {
public String redPaper(String resourceId){
//紅包的發放方式
return "每周末9點發放";
}
public String shopping(String resourceId){
//購物券的發放方式
return "每周三9點發放";
}
public String QQVip(String resourceId){
//qq會員的發放方式
return "每周一0點開始秒殺";
}
}
入參String resourceId是用來查資料庫的,這里簡化了,傳參之后不做處理,
用http呼叫的結果:
@RestController
public class GrantTypeController {
@Autowired
private QueryGrantTypeService queryGrantTypeService;
@PostMapping("/grantType")
public String test(String resourceName){
return queryGrantTypeService.getResult(resourceName);
}
}

用Map+函式式介面也有弊端:
- 你的隊友得會lambda運算式才行啊,他不會讓他自己百度去
最后捋一捋本文講了什么
策略模式通過介面、實作類、邏輯分派來完成,把 if陳述句塊的邏輯抽出來寫成一個類,更好維護,
Map+函式式介面通過Map.get(key)來代替 if-else的業務分派,能夠避免策略模式帶來的類增多、難以俯視整個業務邏輯的問題,
近期熱文推薦:
1.1,000+ 道 Java面試題及答案整理(2022最新版)
2.勁爆!Java 協程要來了,,,
3.Spring Boot 2.x 教程,太全了!
4.20w 程式員紅包封面,快快領取,,,
5.《Java開發手冊(嵩山版)》最新發布,速速下載!
覺得不錯,別忘了隨手點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/423532.html
標籤:其他
下一篇:【第十四期】高德go面經
