1.策略模式
1.1 业务场景
假设有这样的业务场景,需求解析各类不同文件内容,根据不同类型采取不同的解析方式。可能有一些小伙伴就会写出以下的代码:
java
if(type=="txt"){
//按照txt格式解析
}else if(type=="doc"){
//按doc格式解析
}else{
//按照默认格式解析
}
这个代码可能会存在哪些问题呢?
- 如果分支变多,这里的代码就会变得臃肿,难以维护,可读性低。
- 如果你需要接入一种新的解析类型,那只能在原有代码上修改 。
也就是上面代码违背了面向对象编程的开闭原则 以及单一原则。 - 开闭原则(对于扩展是开放的,但是对于修改是封闭的):增加或者删除某个逻辑,都需要修改到原来代码
- 单一原则 (规定一个类应该只有一个发生变化的原因):修改任何类型的分支逻辑代码,都需要改动当前类的代码。
如果你的代码:有多个if...else
等条件分支,并且每个条件分支,可以封装起来替换的,我们就可以使用策略模式来优化。
1.2 策略模式定义
策略模式(Strategy Pattern)是一种比较简单的模式,也叫做政策模式(Policy Pattern)。其定义如下:
Define a family of algorithms,encapsulate each one,and make them interchangeable.(定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。)
举例:假设你跟不同性格类型的小姐姐约会,要用不同的策略,有的请电影比较好,有的则去看演出效果不错,有的去逛街买买买最合适。当然,目的都是为了得到小姐姐的芳心,请看电影、看演出、逛街就是实现不同的策略。
1.3 策略模式使用
- 一个接口或者抽象类,里面两个方法(一个方法匹配类型,一个可替换的逻辑实现方法)
- 不同策略的差异化实现(就是说,不同策略的实现类)
- 使用策略模式
下面是定义策略的接口
java
public interface FileParser {
/**
* 文件类型
* @return
*/
String fileType();
/**
* 解析
* @param inputStream
* @return
* @throws IOException
*/
String parse(InputStream inputStream) throws IOException;
}
不同类型策略具体实现
java
@Component
public class TextFileParser implements FileParser{
@Override
public String fileType() {
return "txt";
}
@Override
public String parse(InputStream inputStream) throws IOException {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"))) {
return reader.lines().collect(Collectors.joining("\n"));
}
}
}
java
@Component
public class JsonFileParser implements FileParser{
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
public String fileType() {
return "json";
}
@Override
public String parse(InputStream inputStream) throws IOException {
return objectMapper.readTree(inputStream).toPrettyString();
}
}
java
@Component
public class CsvFileParser implements FileParser{
@Override
public String fileType() {
return "csv";
}
@Override
public String parse(InputStream inputStream) throws IOException {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"))) {
return reader.lines().collect(Collectors.joining("\n"));
}
}
}
使用策略模式
java
@Component
public class FileParserContext {
private final Map<String, FileParser> parserMap;
@Autowired
public FileParserContext(Map<String, FileParser> parserMap) {
this.parserMap = parserMap;
}
public String parseFile(String fileType, InputStream inputStream) throws IOException {
FileParser parser = parserMap.values().stream()
.filter(value -> value.fileType().equals(fileType))
.findFirst().get();
if (parser != null) {
return parser.parse(inputStream);
} else {
throw new IllegalArgumentException("Unsupported file type: " + fileType);
}
}
}
调用策略模式
java
@RestController
public class TestController {
private final FileParserContext fileParserContext;
@Autowired
public TestController(FileParserContext fileParserContext) {
this.fileParserContext = fileParserContext;
}
@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file, @RequestParam("type") String fileType) {
if (file.isEmpty()) {
return "File is empty";
}
try (InputStream inputStream = file.getInputStream()) {
String content = fileParserContext.parseFile(fileType, inputStream);
// 处理解析后的内容
System.out.println(content);
return "File parsed successfully";
} catch (IOException e) {
e.printStackTrace();
return "Failed to parse file: " + e.getMessage();
}
}
}
完整类图如下