什么是策略模式
官話: 策略模式(Strategy Pattern): 定義一系列算法類,將每一個算法封裝起來,并讓它們可以相互替換,策略模式讓算法獨立于使用它的客戶而變化。
簡單理解就是,針對不同的場景,使用不同的策略進行處理。
優點
- 算法可以自由切換。
- 避免使用多重條件判斷。
- 擴展性良好。
缺點
- 策略類會增多。
- 所有策略類都需要對外暴露。
使用場景
- 如果在一個系統里面有許多類,它們之間的區別僅在于它們的行為,那么使用策略模式可以動態地讓一個對象在許多行為中選擇一種行為。
- 一個系統需要動態地在幾種算法中選擇一種。
- 如果一個對象有很多的行為,如果不用恰當的模式,這些行為就只好使用多重的條件選擇語句來實現。
結構圖
策略模式結構圖
策略模式的簡單示例
場景:最近太熱了,想要降降溫,有什么辦法呢
首先,定義一個降溫策略的接口
public interface CoolingStrategy {
/**
* 處理方式
*/
void handle();
}
定義3種降溫策略;實現策略接口
public class IceCoolingStrategy implements CoolingStrategy {
@Override
public void handle() {
System.out.println("使用冰塊降溫");
}
}
public class FanCoolingStrategy implements CoolingStrategy {
@Override
public void handle() {
System.out.println("使用風扇降溫");
}
}
public class AirConditionerCoolingStrategy implements CoolingStrategy {
@Override
public void handle() {
System.out.println("使用空調降溫");
}
}
定義一個降溫策略的上下文
public class CoolingStrategyContext {
private final CoolingStrategy strategy;
public CoolingStrategyContext(CoolingStrategy strategy) {
this.strategy = strategy;
}
public void coolingHandle() {
strategy.handle();
}
}
測試
public class Main {
public static void main(String[] args) {
CoolingStrategyContext context = new CoolingStrategyContext(new FanCoolingStrategy());
context.coolingHandle();
context = new CoolingStrategyContext(new AirConditionerCoolingStrategy());
context.coolingHandle();
context = new CoolingStrategyContext(new IceCoolingStrategy());
context.coolingHandle();
}
}
運行結果:
使用風扇降溫
使用空調降溫
使用冰塊降溫
以上就是一個策略模式的簡單實現
策略模式的項目實戰
場景
以我自己在工作中遇到的場景為例,《企業微信會話存檔》功能,獲取各種格式的消息內容,進行解析并保存數據。這里只針對消息處理的功能模塊,其他關于《企業微信會話存檔》的功能,有時間整理一下再發出來。
企業微信會話聊天會產生如下多種消息,在SpringBoot項目中應該如何使用策略模式來完成消息的解析呢?
企業微信消息格式
獲取會話內容 - API 看API內容,數據都是json格式。思考應該如何處理:
- 首先,既然要解析各種數據,而每種數據格式結構都不一樣,那么就需要先根據每種消息格式定義各自的對象,然后根據不同的需求,將json格式處理成pojo對象;
- 根據場景,需要定義兩個策略接口,一個是針對普通的文本格式消息的策略,另一個則是需要處理文件格式消息的策略;
- 定義策略處理上下文操作類,用于使用策略
- 每種消息,都會有一些相同的數據,比如發送人、接收人、消息類型等;根據消息類型的不同,使用 key-value 的方式,讓調用者確定應該使用哪個策略來處理數據
因為格式太多,這里只使用兩個格式作為例子
實現
兩個策略接口
public interface Strategy {
/**
* 處理會話存檔的內容
*
* @param content json格式的消息內容
* @return 結果
*/
< T > T handleContent(String content);
}
public interface MediaStrategy {
/**
* 處理會話存檔媒體內容
*
* @param msgData 消息內容
*/
< T > void handleMedia(T msgData);
}
策略的具體實現(偽代碼)
@Component("link")
public class LinkStrategy implements Strategy {
@Override
public LinkPO handleContent(String content) {
// JSON 轉換為具體對象
LinkWrapDTO linkWrapDTO = JacksonUtils.json2Obj(content, LinkWrapDTO.class);
// 將對象處理成業務需要的格式
return Convert.convert(LinkPO.class, linkWrapDTO);
}
}
@Component("image")
public class ImageStrategy implements Strategy, MediaStrategy {
@Autowired
private IMsgFileService msgFileService;
@Override
public ImagePO handleContent(String content) {
// JSON 轉換為具體對象
ImageWrapDTO imageWrapDTO = JacksonUtils.json2Obj(content, ImageWrapDTO.class);
// 將對象處理成業務需要的格式
return Convert.convert(ImagePO.class,imageWrapDTO);
}
@Override
public < T > void handleMedia(T msgData) {
// 將數據格式轉換為具體實現的數據格式
ImagePO imagePo = Convert.convert(ImagePO.class, msgData);
// 調用文件服務,進一步處理文件
msgFileService.newFileTask(imagePo.getImage().getSdkfileid(),
imagePo.getMsgid() + ".jpg", imagePo.getMsgid(), imagePo.getSeq(),
imagePo.getImage().getFilesize(), imagePo.getImage().getMd5sum(), MessageEnum.IMAGE);
}
}
策略上下文
@Component
public class StrategyContext {
@Resource
Map< String, Strategy > strategys = new ConcurrentHashMap< >();
@Resource
Map< String, MediaStrategy > mediaStrategys = new ConcurrentHashMap< >();
public Strategy getStrategy(String component) {
return strategys.get(component);
}
public MediaStrategy getMediaStrategy(String component) {
return mediaStrategys.get(component);
}
}
使用方式(偽代碼)
public class MsgService {
@Resource
private StrategyContext strategyContext;
public void handlerMessage() {
// 請求api獲取消息的json
json = api();
// 轉為通用格式對象
basePo = JsonUtils.json2Obj(json, BasePO.class);
// 選取不同的策略
Strategy strategy = strategyContext.getStrategy(basePo.getMsgType());
// 進行處理
strategy.handleContent(json);
// 關于文件類消息的處理
MediaStrategy mediaStrategy = strategyContext.getMediaStrategy(basePo.getMsgtype());
if (null != mediaStrategy) {
mediaStrategy.handleMedia(basePo);
}
}
}
以上就是策略模式的一種實現方式;
使用策略模式來處理不同格式的消息,雖然多了很多策略類,但是讓整個功能模塊的代碼變得清晰,松耦合,而且很容易擴展和修改,并不會影響其他流程。
小結
從以上的例子很明顯的可以看出,策略模式的靈活性;如果此時企業微信提供了一種新的消息格式,那么根本無需修改之前的代碼,只需要再寫一個新的類,實現消息處理策略的接口,重寫處理方法即可;
了解策略模式的優點和缺點,合理的使用策略模式,會讓你的代碼更加的整潔優雅。
-
接口
+關注
關注
33文章
8596瀏覽量
151147 -
數據
+關注
關注
8文章
7026瀏覽量
89026 -
算法
+關注
關注
23文章
4612瀏覽量
92886 -
API
+關注
關注
2文章
1500瀏覽量
62013
發布評論請先 登錄
相關推薦
評論