策略模式 + 函数式编程 简化代码
前言
- 在软件开发中,往往会遇到多个功能模块存在重复的流程或逻辑,但它们的业务细节又有所不同。为避免代码冗余,提升代码的复用性和可维护性,设计模式等方法提供了很好的解决方案。通过识别和提取通用逻辑,开发者可以将相似的代码抽象为更加灵活和扩展性强的结构,适用于不同场景的需求。
- 本文将展示如何从重复的业务代码中提取共性,逐步优化并提升代码的可维护性与灵活性,最终形成一个更加通用、扩展性强的解决方案。
- 不必关心我这里的业务逻辑,仅仅关心模板的提取。
现状分析:重复代码的问题
- 在原有实现中,每个文档生成 API 都包含相同的文件下载处理逻辑,如下所示
1 |
|
- 即使抽取公共代码作为独立方法,依然会存在重复的逻辑
1 |
|
- 存在的问题:
- 代码重复:每个 API 都要写相同的文件下载逻辑,违反
DRY
(Don’t Repeat Yourself)原则。 - 扩展性差:如果需要修改文件下载方式,所有 API 代码都需要调整。
- 维护成本高:新增文档类型时,需要复制粘贴代码,容易出现不一致性问题。
- 代码重复:每个 API 都要写相同的文件下载逻辑,违反
使用模板方法模式优化代码
什么是模板方法模式?
- 模板方法模式(Template Method Pattern)是一种行为设计模式,它定义一个算法的通用流程,并允许子类或外部方法提供具体实现。它的核心思想是将通用逻辑抽取到父类(或公共组件)中,让子类(或具体方法)实现可变部分。
代码优化:引入 DocGenerateExecutor
- 为了避免继承带来的复杂性,我采用了
策略模式
+函数式接口
的方式,避免传统模板方法模式的局限性。核心思想是将文件下载逻辑封装到一个可复用的执行器 DocGenerateExecutor 中,并通过函数式接口让不同业务代码提供具体的文档生成逻辑。- 创建 DocGenerateExecutor 统一处理文档下载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class DocGenerateExecutor {
// 定义函数式接口,让外部提供具体文档生成逻辑
public interface DocGenerateFun {
String executor() throws Exception;
}
// 通用的文档生成和下载逻辑
public void generateDoc(DocGenerateFun fun, HttpServletResponse response) throws Exception {
String diskPath = fun.executor();
CommonUtil.setContentType(response, diskPath);
response.setHeader("Content-Disposition", "attachment;filename=" +
java.net.URLEncoder.encode(FilenameUtils.getName(diskPath), "UTF-8").replaceAll("\\+", "%20")
);
ServletOutputStream outputStream = response.getOutputStream();
FileUtils.copyFile(new File(diskPath), outputStream);
outputStream.close();
}
}- 调用 DocGenerateExecutor 处理文档下载
1
2
3
4
public void generateOpenReport(String json, String orderId, HttpServletResponse response) throws Exception {
docGenerateExecutor.generateDoc(() -> orderConsumerService.generateOpenReport(JSONObject.parseObject(json), orderId), response);
}
代码优化的效果与优势
优化后代码的优势
优化点 | 传统实现 | 优化后实现 |
---|---|---|
代码复用性 | 每个 API 复制相同的下载逻辑 | 只需调用 DocGenerateExecutor |
扩展性 | 需要修改多个 API 代码 | 只需修改 DocGenerateExecutor |
可维护性 | 代码冗余,容易引入 Bug | 代码简洁,降低维护成本 |
代码行数减少
-
传统代码需要在每个 API 里写一遍文件下载逻辑,而优化后只需调用 generateDoc(),减少了大量重复代码。
-
如果需要调整下载逻辑,比如支持流式下载、日志记录等,只需修改 DocGenerateExecutor 一处,所有 API 无需修改。
适配不同的文档生成逻辑
- 只需要传入不同的 Lambda 表达式,即可适配不同的文档生成逻辑。
无须继承
,避免 Java 传统模板方法模式的类爆炸
问题。
评论