一、策略模式
背景
针对某种业务可能存在多种实现方式;传统方式是通过传统if...else...或者switch代码判断;
弊端:
- 代码可读性差
- 扩展性差
- 难以维护
策略模式简介
策略模式是一种行为型模式,它将对象和行为分开,将行为定义为一个行为接口和具体行为的实现。
组成:
- 抽象策略类(Strategy):策略的抽象;
- 具体策略类(ConcreteStrategy):具体的策略实现,一种具体实现;
- 环境类(Context):用来操作策略的上下文环境;
二、代码实现
以文件存储方式为例
抽象策略类
java
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;
}
具体策略实现
本地存储
java
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
@Slf4j
public class LocalStoreStrategyImpl implements FileStoreStrategy {
@Override
public String getType() {
return "LOCAL";
}
@Override
public void uploadFile(MultipartFile file) throws Exception {
log.info("upload file by local");
}
}
minio存储
java
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
@Slf4j
public class MinioStoreStrategyImpl implements FileStoreStrategy {
@Override
public String getType() {
return "MINIO";
}
@Override
public void uploadFile(MultipartFile file) throws Exception {
log.info("upload file by minio");
}
}
策略上下文环境
java
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
*/
@Component
public 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;
}
}
调用
java
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 {
@Autowired
private FileStoreStrategyContext fileStoreStrategyContext;
@GetMapping("/upload")
public String upload(String type) throws Exception {
FileStoreStrategy fileStoreStrategy = fileStoreStrategyContext.getStrategy(type);
fileStoreStrategy.uploadFile(null);
return fileStoreStrategy.getType();
}
}
扩展
如果新增一种存储方式,只需增加一个策略实现类,实现FileStoreStrategy接口,重写getType方法,然后再实现具体的业务逻辑;