Java 工厂模式 + 策略模式实战:工具管理器的设计与实现
在日常开发中,我们经常会遇到「需要根据不同的业务逻辑选择不同实现类」的场景。比如:文件操作可能有读取、写入、修改、删除等多种方式,如果我们在业务代码中使用大量的 if-else
来区分,会导致代码臃肿且难以维护。
本文将结合 工厂模式(Factory Pattern) 和 策略模式(Strategy Pattern),通过一个 工具管理器(ToolManager) 的案例,来展示如何优雅地管理和调用不同的工具。
一、模式介绍
1. 工厂模式
工厂模式的核心思想是:将对象的创建与使用解耦。
调用方不需要关心对象的具体实现,而只需要通过工厂方法获取对象即可。
在本文中,ToolManager
就是一个工厂,负责 统一注册和管理所有工具实例。
2. 策略模式
策略模式强调:定义一系列算法(策略),并且可以在运行时自由切换。
调用方只需要依赖抽象接口,而不需要知道具体的实现细节。
在本文中,每个工具(如 FileReadTool
、FileWriteTool
)就是一个具体策略,统一实现了 BaseTool
抽象类。
二、使用场景
这种「工厂模式 + 策略模式」的组合,非常适合以下场景:
多实现类管理
比如支付系统中的 微信支付 / 支付宝支付 / 银行卡支付,都可以作为不同的策略,由工厂统一管理。动态扩展
新增一种工具(比如FileUploadTool
),只需要实现BaseTool
并交给工厂管理,而不需要改动原有逻辑,符合 开闭原则。业务逻辑解耦
调用方只依赖抽象接口(BaseTool
),而不依赖具体实现,业务逻辑更加清晰。
三、代码示例
下面给出完整的示例代码,使用 Spring + Hutool 结合实现。
1. 定义工具基类(抽象类)
package com.ming.mingaicode.ai.tools;import cn.hutool.json.JSONObject;/*** 工具基类,定义所有工具的通用接口*/
public abstract class BaseTool {public abstract String getToolName();public abstract String getDisplayName();public String generateToolRequestResponse() {return String.format("\n\n[选择工具🔧] %s\n\n", getDisplayName());}public abstract String generateToolExecutedResult(JSONObject arguments);
}
2. 定义多个工具实现类(具体策略)
文件目录读取工具
@Slf4j
@Component
public class FileDirReadTool extends BaseTool{@Overridepublic String getToolName() { return "readDir"; }@Overridepublic String getDisplayName() { return "读取目录"; }@Overridepublic String generateToolExecutedResult(JSONObject arguments) {String relativeDirPath = arguments.getStr("relativeDirPath");if (StrUtil.isEmpty(relativeDirPath)) {relativeDirPath = "根目录";}return String.format("[工具调用] %s %s", getDisplayName(), relativeDirPath);}
}
文件修改工具
@Slf4j
@Component
public class FileModifyTool extends BaseTool{@Overridepublic String getToolName() { return "modifyFile"; }@Overridepublic String getDisplayName() { return "修改文件"; }@Overridepublic String generateToolExecutedResult(JSONObject arguments) {String relativeFilePath = arguments.getStr("relativeFilePath");String oldContent = arguments.getStr("oldContent");String newContent = arguments.getStr("newContent");return String.format("""[工具调用] %s %s替换前:```%s```替换后:```%s```""", getDisplayName(), relativeFilePath, oldContent, newContent);}
}
文件写入工具
@Slf4j
@Component
public class FileWriteTool extends BaseTool{@Overridepublic String getToolName() { return "writeFile"; }@Overridepublic String getDisplayName() { return "写入文件"; }@Overridepublic String generateToolExecutedResult(JSONObject arguments) {String relativeFilePath = arguments.getStr("relativeFilePath");String suffix = FileUtil.getSuffix(relativeFilePath);String content = arguments.getStr("content");return String.format("""[工具调用] %s %s```%s%s```""", getDisplayName(), relativeFilePath, suffix, content);}
}
(其他工具如 FileReadTool
、FileDeleteTool
也类似,不再赘述)
3. 工厂管理器(ToolManager)
@Slf4j
@Component
public class ToolManager {@Resourceprivate BaseTool[] tools;private final Map<String, BaseTool> toolMap = new HashMap<>();@PostConstructpublic void initTools() {for (BaseTool tool : tools) {toolMap.put(tool.getToolName(), tool);log.info("注册工具: {} -> {}", tool.getToolName(), tool.getDisplayName());}log.info("工具管理器初始化完成,共注册 {} 个工具", toolMap.size());}public BaseTool getTool(String toolName) {return toolMap.get(toolName);}public BaseTool[] getAllTools() {return tools;}
}
4. 使用方式
// 处理工具请求
case TOOL_REQUEST -> {BaseTool tool = toolManager.getTool(toolRequestMessage.getName());return tool.generateToolRequestResponse();
}// 处理工具执行结果
case TOOL_EXECUTED -> {BaseTool tool = toolManager.getTool(toolExecutedMessage.getName());String result = tool.generateToolExecutedResult(jsonObject);return String.format("\n\n%s\n\n", result);
}
四、方法解析
抽象基类
BaseTool
统一了所有工具的接口(名字、展示名、执行结果格式化)。
保证扩展新工具时,调用方无需修改原有逻辑。
具体工具类(策略)
每个工具都实现了自己的
generateToolExecutedResult
方法,遵循 策略模式。
ToolManager 工厂
自动扫描所有
BaseTool
的子类(Spring 注入)。通过
Map
保存工具名称和实例的映射,支持快速查找和调用。
五、总结
本文通过 工厂模式 + 策略模式 结合的方式,构建了一个可扩展、可维护的 工具管理器:
工厂模式负责统一管理实例。
策略模式负责封装不同的业务逻辑。
新增功能时,只需要 新增一个实现类,无需修改现有代码,真正做到 开闭原则。
这种设计思想在 支付系统、权限系统、AI 工具调用 等场景下都有广泛应用,能够显著提升代码的可维护性和扩展性。