Java中实现API链式调用的最优设计模式
针对你这种需要按顺序调用API、前一步响应作为后一步请求参数的场景,我推荐两种通用化的设计方案,既能避免重复的硬编码逻辑,又能满足你“初始阶段不了解请求上下文”的需求:
方案1:函数式接口 + 动态步骤链(最推荐)
这种方案利用Java 8+的函数式编程特性,让你可以动态组装API调用步骤——哪怕运行时才确定要执行哪些步骤,也能灵活添加。核心是用一个上下文类保存请求状态和累计输出,再把每个API调用封装成独立的步骤单元。
第一步:定义上下文类
用来统一管理请求对象、累计输出等状态:
public class ApiCallContext { private YourRequest req; // 替换成你的实际请求类 private StringBuilder output = new StringBuilder(); public ApiCallContext(YourRequest initialReq) { this.req = initialReq; } // 添加输出内容 public void appendOutput(String content) { output.append(content); } // 获取最终拼接的输出 public String getFinalOutput() { return output.toString(); } // Getter和Setter,按需提供 public YourRequest getReq() { return req; } public void setReq(YourRequest req) { this.req = req; } }
第二步:定义步骤接口
用函数式接口简化步骤的定义:
@FunctionalInterface public interface ApiStep { void execute(ApiCallContext context); }
第三步:封装每个API调用为步骤
把你原来的每一段API调用逻辑,拆成独立的ApiStep实现:
// 第一个API调用步骤 public ApiStep firstApiCall() { return context -> { Response res = execute(context.getReq()); // 这里是你的execute方法 context.appendOutput(res.getOut()); context.getReq().setXYZ(res.getXYZ()); // 更新请求参数 }; } // 第二个API调用步骤 public ApiStep secondApiCall() { return context -> { Response res = execute(context.getReq()); context.appendOutput(res.getOut()); context.getReq().setABC(res.getABC()); }; } // 第三个API调用步骤 public ApiStep thirdApiCall() { return context -> { Response res = execute(context.getReq()); context.appendOutput(res.getOut()); }; }
第四步:构建执行器
用来按顺序执行所有步骤,支持动态添加:
public class ApiCallExecutor { private final List<ApiStep> steps = new ArrayList<>(); // 链式调用添加步骤 public ApiCallExecutor addStep(ApiStep step) { steps.add(step); return this; } // 执行所有步骤并返回最终结果 public String execute(YourRequest initialReq) { ApiCallContext context = new ApiCallContext(initialReq); for (ApiStep step : steps) { step.execute(context); } return context.getFinalOutput(); } }
使用示例
你可以根据运行时的上下文动态添加步骤,比如根据初始请求的参数决定要不要跳过某个步骤:
public static void main(String[] args) { YourRequest initialReq = new YourRequest(); // 初始化请求参数... ApiCallExecutor executor = new ApiCallExecutor() .addStep(firstApiCall()) .addStep(secondApiCall()); // 比如根据初始请求的某个条件,决定是否添加第三个步骤 if (initialReq.needThirdCall()) { executor.addStep(thirdApiCall()); } String finalOutput = executor.execute(initialReq); System.out.println("Final response::" + finalOutput); }
这个方案的优势:
- 每个API调用逻辑完全解耦,单独维护
- 支持动态调整步骤(添加、移除、调整顺序),完美适配“初始不了解上下文”的场景
- 代码简洁,利用函数式接口减少冗余
方案2:模板方法模式(适合固定流程场景)
如果你的API调用流程有固定的骨架(比如必须按A→B→C的顺序执行,只是每个步骤的细节可能变化),可以用模板方法模式封装固定流程,具体步骤由子类实现。
定义抽象模板类
封装固定的执行流程,把可变的步骤抽象成方法:
public abstract class AbstractApiFlow { protected YourRequest req; protected StringBuilder output = new StringBuilder(); public AbstractApiFlow(YourRequest initialReq) { this.req = initialReq; } // 模板方法:固定执行流程 public final String runFlow() { executeFirstApi(); executeSecondApi(); executeThirdApi(); return output.toString(); } // 抽象方法:每个步骤的具体实现由子类完成 protected abstract void executeFirstApi(); protected abstract void executeSecondApi(); protected abstract void executeThirdApi(); // 通用的API执行方法,抽出来复用 protected Response callApi(YourRequest request) { return execute(request); // 你的execute方法 } }
实现具体流程类
public class DefaultApiFlow extends AbstractApiFlow { public DefaultApiFlow(YourRequest initialReq) { super(initialReq); } @Override protected void executeFirstApi() { Response res = callApi(req); output.append(res.getOut()); req.setXYZ(res.getXYZ()); } @Override protected void executeSecondApi() { Response res = callApi(req); output.append(res.getOut()); req.setABC(res.getABC()); } @Override protected void executeThirdApi() { Response res = callApi(req); output.append(res.getOut()); } }
使用示例
public static void main(String[] args) { YourRequest initialReq = new YourRequest(); AbstractApiFlow flow = new DefaultApiFlow(initialReq); String finalOutput = flow.runFlow(); System.out.println("Final response::" + finalOutput); }
这个方案适合流程相对固定的场景,如果后续有不同的流程变体,可以创建不同的子类,但灵活性不如第一个方案。
为什么责任链模式不适用?
你说得对,责任链模式更适合“请求传递,每个处理器决定是否处理”的场景,比如请求过滤、日志处理等。它的核心是请求的分发或过滤,而不是你这种必须按顺序执行、每个步骤依赖前一步结果修改请求状态的流水线场景——而且责任链通常需要提前构建好链的结构,不太适配“初始不了解上下文”的动态需求。
内容的提问来源于stack exchange,提问作者goosebump
相关产品推荐
相关产品推荐

