设计模式之策略模式

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();
        }
    }
}

完整类图如下

相关推荐
pingzhuyan20 分钟前
03(总)-docker篇 Dockerfile镜像制作(jdk,jar)与jar包制作成docker容器方式
java·docker·jar
caihuayuan41 小时前
Redis奇幻之旅(三)1.redis客户端与服务端
java·大数据·sql·spring·课程设计
匆匆整棹还2 小时前
关于tomcat乱码和idea中控制台乱码的问题
java·tomcat·intellij-idea
何似在人间5753 小时前
SpringAI+DeepSeek大模型应用开发——1 AI概述
java·人工智能·spring·springai
进击的圆儿3 小时前
策略模式简单介绍
策略模式
匹马夕阳3 小时前
Java开发中的设计模式之观察者模式详细讲解
java·观察者模式·设计模式
风铃儿~3 小时前
Java微服务注册中心深度解析:环境隔离、分级模型与Eureka/Nacos对比
java·分布式·微服务·面试
赤橙红的黄4 小时前
Spring Boot中接入DeepSeek的流式输出
java·服务器·javascript
小样vvv4 小时前
【AI】IDEA 集成 AI 工具的背景与意义
java·人工智能·intellij-idea
sg_knight4 小时前
Spring Cloud 2024.x智能运维:AI驱动的故障预测与自愈
java·运维·人工智能·spring boot·spring cloud