一、策略模式

背景

针对某种业务可能存在多种实现方式;传统方式是通过传统if…else…或者switch代码判断;

弊端:

  • 代码可读性差
  • 扩展性差
  • 难以维护

策略模式简介

策略模式是一种行为型模式,它将对象和行为分开,将行为定义为一个行为接口和具体行为的实现。

组成:

  • 抽象策略类(Strategy):策略的抽象;
  • 具体策略类(ConcreteStrategy):具体的策略实现,一种具体实现;
  • 环境类(Context):用来操作策略的上下文环境;

二、代码实现

以文件存储方式为例

抽象策略类

package com.qiangesoft.file.core;import org.springframework.web.multipart.MultipartFile;/** * 文件存储策略接口 * * @author qiangesoft * @date 2024-01-06 */public interface FileStoreStrategy {/** * 存储方式 * * @return */String getType();/** * 上传文件 * * @param file * @return * @throws Exception */void uploadFile(MultipartFile file) throws Exception;}

具体策略实现

本地存储

package com.qiangesoft.file.core.local;import com.qiangesoft.file.core.FileStoreStrategy;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Component;import org.springframework.web.multipart.MultipartFile;/** * 文件本地存储 * * @author qiangesoft * @date 2024-01-06 */@Component@Slf4jpublic class LocalStoreStrategyImpl implements FileStoreStrategy {@Overridepublic String getType() {return "LOCAL";}@Overridepublic void uploadFile(MultipartFile file) throws Exception {log.info("upload file by local");}}

minio存储

package com.qiangesoft.file.core.minio;import com.qiangesoft.file.core.FileStoreStrategy;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Component;import org.springframework.web.multipart.MultipartFile;/** * 文件minio对象存储 * * @author qiangesoft * @date 2024-01-06 */@Component@Slf4jpublic class MinioStoreStrategyImpl implements FileStoreStrategy {@Overridepublic String getType() {return "MINIO";}@Overridepublic void uploadFile(MultipartFile file) throws Exception {log.info("upload file by minio");}}

策略上下文环境

package com.qiangesoft.file.core;import org.springframework.stereotype.Component;import java.util.List;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;/** * 文件存储策略上下文 * * @author qiangesoft * @date 2024-01-06 */@Componentpublic class FileStoreStrategyContext {/** * 策略实现类上下文 */private final Map<String, FileStoreStrategy> strategyMap = new ConcurrentHashMap<>();/** * 利用Spring的发现机制,将实现了FileStoreStrategy的类都放到strategyMap里面 */public FileStoreStrategyContext(List<FileStoreStrategy> fileStoreStrategyList) {for (FileStoreStrategy strategy : fileStoreStrategyList) {String type = strategy.getType();if (this.strategyMap.containsKey(type)) {throw new RuntimeException(String.format("Strategy [%s] is repeat!", type));}this.strategyMap.put(type, strategy);}}/** * 获取具体的策略实现类 * * @param storeType * @return */public FileStoreStrategy getStrategy(String storeType) {FileStoreStrategy strategy = strategyMap.get(storeType);if (strategy == null) {throw new RuntimeException(String.format("Strategy [%s] is not found!", storeType));}return strategy;}}

调用

package com.qiangesoft.file.demo;import com.qiangesoft.file.core.FileStoreStrategy;import com.qiangesoft.file.core.FileStoreStrategyContext;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/** * Demo * * @author qiangesoft * @date 2024-01-08 */@RestController@RequestMapping("/demo")public class DemoController {@Autowiredprivate FileStoreStrategyContext fileStoreStrategyContext;@GetMapping("/upload")public String upload(String type) throws Exception {FileStoreStrategy fileStoreStrategy = fileStoreStrategyContext.getStrategy(type);fileStoreStrategy.uploadFile(null);return fileStoreStrategy.getType();}}



扩展

如果新增一种存储方式,只需增加一个策略实现类,实现FileStoreStrategy接口,重写getType方法,然后再实现具体的业务逻辑;

案例代码

点击下载