适配不同输入参数数量算法的最优设计模式选型
嘿,这个场景我太有共鸣了——碰到两个几乎一模一样的算法,就差参数多了个纬度,硬套模板模式非要传个带null纬度的对象,确实别扭得很。这里有几个更清爽的解决思路,你可以试试看:
方案1:用组合模式替代抽象模板类
别纠结抽象类的模板结构了,把90%的重复逻辑抽成一个独立的工具类,让两个算法类直接依赖它,各自处理自己的参数适配就行。这样既保留了代码复用,又不会出现多余的null参数。
先写公共核心逻辑:
public class CommonAlgorithmLogic { // 第一个算法用的核心计算逻辑 public double coreCalculate(double longitude) { // 这里放两个算法90%重复的计算代码 return longitude * 1.2; // 示例逻辑 } // 第二个算法用的重载版本,在通用逻辑基础上加纬度处理 public double coreCalculate(double longitude, double latitude) { double baseResult = coreCalculate(longitude); // 这里加第二个算法特有的纬度相关计算 return baseResult + (latitude * 0.8); } // 两个算法共用的保存逻辑 public void coreSave(double result, String algorithmType) { // 通用保存代码,比如写入数据库、日志等 System.out.println("Saving result for " + algorithmType + ": " + result); } }
然后第一个算法类(只需要经度):
public class LongitudeOnlyAlgorithm { private final CommonAlgorithmLogic commonLogic = new CommonAlgorithmLogic(); public void run(double longitude) { double result = commonLogic.coreCalculate(longitude); commonLogic.coreSave(result, "longitude-only"); } }
第二个算法类(需要经纬度):
public class LongLatAlgorithm { private final CommonAlgorithmLogic commonLogic = new CommonAlgorithmLogic(); public void run(double longitude, double latitude) { double result = commonLogic.coreCalculate(longitude, latitude); commonLogic.coreSave(result, "long-lat"); } }
调用的时候直接传各自需要的参数就行,干净利落,完全不用处理null。
方案2:函数式接口+默认方法(Java 8+)
如果还是想保留“定义执行流程”的模板特性,可以用接口的默认方法来封装通用流程,同时用重载或默认方法处理参数差异:
public interface Algorithm { // 封装通用执行流程:计算→保存 default void execute(double longitude) { double result = calculate(longitude); save(result); } // 给第二个算法重载的执行方法 default void execute(double longitude, double latitude) { double result = calculate(longitude, latitude); save(result); } // 基础计算逻辑(两个算法共用的90%代码) double calculate(double longitude); // 带纬度的计算,默认实现调用基础逻辑+空扩展,第一个算法不用管 default double calculate(double longitude, double latitude) { return calculate(longitude); } // 通用保存逻辑 default void save(double result) { // 共用的保存代码 System.out.println("Saving result: " + result); } }
第一个算法实现:
public class LongitudeOnlyAlgorithm implements Algorithm { @Override public double calculate(double longitude) { // 核心计算逻辑 return longitude * 1.2; } }
第二个算法只需要扩展纬度相关的计算:
public class LongLatAlgorithm implements Algorithm { @Override public double calculate(double longitude) { // 和第一个算法完全一样的核心逻辑 return longitude * 1.2; } @Override public double calculate(double longitude, double latitude) { // 在核心逻辑基础上加纬度处理 double baseResult = super.calculate(longitude); return baseResult + (latitude * 0.8); } }
这个方案既保留了模板模式的流程封装,又让每个算法只处理自己需要的参数,没有多余的null。
方案3:Builder模式封装参数(适合参数可能扩展的场景)
如果以后还可能加更多参数(比如海拔、时间戳),用Builder模式封装参数是个更健壮的选择,既能保证必要参数不缺失,又能让每个算法只取自己需要的参数:
先定义参数Builder:
public class AlgorithmParams { private final double longitude; private Double latitude; private AlgorithmParams(Builder builder) { this.longitude = builder.longitude; this.latitude = builder.latitude; } public static class Builder { private double longitude; private Double latitude; public Builder longitude(double longitude) { this.longitude = longitude; return this; } public Builder latitude(double latitude) { this.latitude = latitude; return this; } public AlgorithmParams build() { // 校验必要参数,比如经度必须传 return new AlgorithmParams(this); } } // Getter方法 public double getLongitude() { return longitude; } public Double getLatitude() { return latitude; } }
然后调整模板类,用这个参数对象:
public abstract class AlgorithmTemplate { public final void execute(AlgorithmParams params) { double result = calculate(params); save(result); } protected abstract double calculate(AlgorithmParams params); protected void save(double result) { // 通用保存逻辑 System.out.println("Saving result: " + result); } }
第一个算法实现:
public class LongitudeOnlyAlgorithm extends AlgorithmTemplate { @Override protected double calculate(AlgorithmParams params) { // 只用到经度,完全不用管纬度 return params.getLongitude() * 1.2; } }
第二个算法实现:
public class LongLatAlgorithm extends AlgorithmTemplate { @Override protected double calculate(AlgorithmParams params) { double baseResult = params.getLongitude() * 1.2; // 用到纬度,这里可以放心用,因为调用时会传 return baseResult + (params.getLatitude() * 0.8); } }
调用的时候:
// 第一个算法只传经度 new LongitudeOnlyAlgorithm().execute(new AlgorithmParams.Builder().longitude(120.0).build()); // 第二个算法传经纬度 new LongLatAlgorithm().execute(new AlgorithmParams.Builder().longitude(120.0).latitude(30.0).build());
这个方案的好处是参数扩展灵活,而且不会出现不必要的null,因为Builder可以控制哪些参数是可选的。
内容的提问来源于stack exchange,提问作者Aleksander Monk
相关产品推荐
相关产品推荐

