实现模板方法模式遇参数适配难题:不同具体实现参数需求不同
兄弟,这种情况我太懂了——用模板方法模式规范流程的时候,参数传递的冗余和扩展性问题简直是家常便饭。你提到的Parameter Object模式是个好方向,但还有几个更适配这个场景的思路,我给你掰扯清楚:
1. 进阶版Parameter Object模式(首推)
别只是简单把参数打包成一个对象,咱们可以做分层的参数对象,或者用建造者模式让参数对象的创建更优雅。这样既避免了传递一堆零散参数,后续加新参数也不用改模板方法的签名:
// 定义包含所有可能参数的对象,用建造者模式优化创建 public class ProcessParams { private final String paramA; private final Integer paramB; private final Double paramC; private ProcessParams(Builder builder) { this.paramA = builder.paramA; this.paramB = builder.paramB; this.paramC = builder.paramC; } // getter方法 public String getParamA() { return paramA; } public Integer getParamB() { return paramB; } public Double getParamC() { return paramC; } public static class Builder { private String paramA; private Integer paramB; private Double paramC; public Builder paramA(String val) { paramA = val; return this; } public Builder paramB(Integer val) { paramB = val; return this; } public Builder paramC(Double val) { paramC = val; return this; } public ProcessParams build() { return new ProcessParams(this); } } } // 抽象类的模板方法,只传参数对象 public abstract class AbstractProcessor { public void templateMethod(ProcessParams params) { step1(); step2(params); step3(); } protected abstract void step2(ProcessParams params); private void step1() { /* 通用逻辑 */ } private void step3() { /* 通用逻辑 */ } } // 具体实现只拿自己需要的参数 public class ConcreteProcessorA extends AbstractProcessor { @Override protected void step2(ProcessParams params) { String neededParam = params.getParamA(); // 业务逻辑处理 } }
后续如果有新的具体实现需要paramD,只需要给ProcessParams加字段和Builder方法,模板方法的签名完全不用动,具体实现也只取自己要的参数,完美解决你的两个痛点。
2. 上下文对象模式(灵活度拉满)
如果你的参数类型多变,或者流程中需要动态传递数据,可以搞一个上下文对象,把所有参数都存在里面,步骤方法直接从上下文取:
public class ProcessContext { private final Map<String, Object> contextData = new HashMap<>(); public <T> void put(String key, T value) { contextData.put(key, value); } @SuppressWarnings("unchecked") public <T> T get(String key) { return (T) contextData.get(key); } } public abstract class AbstractProcessor { protected ProcessContext context; public void templateMethod(ProcessContext context) { this.context = context; step1(); step2(); step3(); } protected abstract void step2(); private void step1() { /* 通用逻辑 */ } private void step3() { /* 通用逻辑 */ } } // 具体实现按需获取参数 public class ConcreteProcessorB extends AbstractProcessor { @Override protected void step2() { Integer neededParam = context.get("paramB"); // 业务逻辑处理 } }
这种方式的好处是极端灵活,不管后续加什么类型的参数,都不用改任何方法签名,直接往上下文里塞就行。唯一要注意的是类型转换的安全性,你可以给上下文加一些类型安全的get方法(比如getInteger(String key))来避免强制转换的问题。
3. 反向参数准备(适合参数由具体实现生成的场景)
如果你的参数不是外部传入,而是由具体实现自己生成的,还可以把“参数准备”的逻辑交给具体实现:
public abstract class AbstractProcessor { public void execute() { ProcessParams params = prepareParams(); templateMethod(params); } // 具体实现自己准备需要的参数 protected abstract ProcessParams prepareParams(); private void templateMethod(ProcessParams params) { step1(); step2(params); step3(); } protected abstract void step2(ProcessParams params); private void step1() { /* 通用逻辑 */ } private void step3() { /* 通用逻辑 */ } }
这种方式让具体实现完全掌控参数,模板方法只负责流程执行,不过如果你的参数是外部传入的,这个思路可能就不太适用了。
综合来看,进阶版的Parameter Object模式是最贴合你需求的:既解决了冗余参数传递的问题,又保证了后续的扩展性,不用修改模板方法的签名。如果你的场景参数类型特别多变,上下文对象模式会是更好的选择。
内容的提问来源于stack exchange,提问作者Adolfo Perez

