淺談用SpringBoot實現策略模式
問題的提出
閱讀別人代碼的時候最討厭遇到的就是大段大段的if-else分支語句,一般來說讀到下面的時候就忘瞭上面在判斷什麼瞭。很多資料上都會講到使用策略模式來改進這種代碼邏輯。
策略模式的類圖如下:
隻需要按照這個圖寫代碼就可以瞭。
策略模式代碼的實現
借助Spring框架我們能夠輕松的實現策略模式。
舉一個簡單的例子,我們去咖啡店買咖啡的時候,會根據自己的喜好和胃容量選擇大小杯。那麼我們就要實現一個CoffeeStategy:
package com.example.demo.strategy; public interface CoffeeStrategy { void offer(); }
接下來就是各種具體策略的實現瞭,以中杯咖啡為例:
package com.example.demo.strategy; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Component("MID") @Slf4j public class MidCoffee implements CoffeeStrategy { @Override public void offer() { log.info("你的中杯咖啡"); } }
用Component註解給這個類起一個名字叫做MID,這個在後面的應用上下文中有起效。現在就開始定義應用上下文類:
package com.example.demo.strategy; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Map; @Service public class CoffeeContext { @Autowired private Map<String, CoffeeStrategy> coffeeStrategyMap; public void getCoffee(String size) { this.coffeeStrategyMap.get(size).offer(); } }
因為是使用瞭Spring框架,所有的Bean都被Spring自行管理,啟動之後,Map中會有兩個元素:{“MID”:MidCoffee}和{“LARGE”:LargeCoffee}。在具體的業務邏輯中,隻需要引入應用上下文類,每次使用getCoffee方法就可以瞭。
比如這個Controller方法:
@GetMapping("/get") public void getCoffee(@Param("size") String size) { this.coffeeContext.getCoffee(size); }
請求這個接口,我們能在後臺看到具體的日志內容:
2021-09-30 22:46:32.550 INFO 15628 — [nio-8099-exec-1] com.example.demo.strategy.LargeCoffee : 您的大杯咖啡
2021-09-30 22:46:39.201 INFO 15628 — [nio-8099-exec-7] com.example.demo.strategy.LargeCoffee : 您的大杯咖啡
進一步的思考
之前寫過Component中起的名字有奇效。如果我們沒有用Spring框架去實現策略模式,那麼我們的代碼要如何編寫呢?
首先可以肯定的是策略接口和策略實現類是不需要變的。需要變的地方就是應用上下文瞭,因為不存在自動註入瞭。這段代碼就會變成大致這樣:
package com.example.demo.strategy; public class CoffeeContext { CoffeeStrategy coffeeStrategy; public CoffeeContext(CoffeeStrategy coffeeStrategy) { this.coffeeStrategy = coffeeStrategy; } public void getCoffee() { this.coffeeStrategy.offer(); } }
這樣,在實際使用的時候,我需要先新建一個具體的實現類對象,然後將這個對象傳入策略應用上下文去。這種方式怎麼看著都沒有Spring的實現方式優雅。
CoffeeStrategy mid = new MidCoffee(); CoffeeContext context = new CoffeeContext(mid); context.getCoffee();
在我實際改造代碼的過程中我發現有些策略其實是一樣的,隻是個別參數不同罷瞭。我對接的是各個業務供應商,有些供應商的接口邏輯式樣的,隻是URL和USERNAME不一樣罷瞭。於是好幾個策略實現類的代碼重復很嚴重,這個時候我使用瞭Java8開始提供的接口default方法。這種方法的好處就是能將這種一樣的邏輯提取到interface中,隻要實現類不重寫,那麼就會默認使用default方法。
這樣改造之後,我的代碼又精簡瞭很多。
心得體會
在我接手現在這個項目代碼的時候,之前的程序員將代碼寫的很直白,就是可以不用任何的設計,直接寫邏輯。這也沒錯,可是用IDEA的時候會各種提示重復代碼啊之類的,讓人看著不開心。而且還有大量的if-else分支讓人摸不著頭腦。
在我大刀闊斧的改造之後,代碼行數越來越少,但是可讀性卻越來越高。
此時我是比較理解GoF在設計模式這本書裡提到的一句話,大致意思就是開發一個面向對象的程序並不簡單。
到此這篇關於淺談用SpringBoot實現策略模式的文章就介紹到這瞭,更多相關SpringBoot 策略模式內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Spring框架學習之Spring @Autowired實現自動裝配的代碼
- Java中常用的設計模式之策略模式詳解
- SpringBoot中創建的AOP不生效的原因及解決
- 基於SpringBoot開機啟動與@Order註解
- 淺談SpringBoot Bean加載優先級的問題