父类方法中仅子类使用的参数是否属于代码坏味道?
问题结论
这种写法属于典型的*冗余参数(Dead Parameter)*代码坏味道,核心问题如下:
- 父类方法签名引入了完全不需要的依赖,所有调用父类
doSomething的位置都需要无意义传入Bar实例,拉高了不必要的调用成本 - 违反最小知识原则,父类不需要感知
Bar的存在却被迫在方法签名中声明 - 后续新增A的其他子类时,都要被迫兼容这个无用参数,扩展成本高
推荐解决方案
可根据你的业务场景选择以下三种方案:
方案1:拆分父类方法签名,子类按需重载
适合父类方法本身不需要Bar、子类的扩展逻辑属于自身独有场景的情况,完全不破坏父类原有定义:
// 父类A调整后,仅保留自身逻辑需要的参数 protected String doSomething(Foo foo) { return foo.getString(); }
// 子类B调整后,不需要重写父类方法,直接重载新方法即可 protected String doSomething(Foo foo, Bar bar) { if (Objects.equals(bar.getType(), "something")) { return bar.getString(); } return doSomething(foo); }
方案2:封装上下文对象统一多态签名
适合多态调用必须统一方法签名(上层逻辑统一调用A类的doSomething,子类需要差异化实现)的场景:
首先封装所有可能用到的参数为独立上下文类:
@Data public class DoSomethingContext { private Foo foo; private Bar bar; }
父类方法调整为接收上下文对象,仅提取自身需要的字段:
protected String doSomething(DoSomethingContext context) { return context.getFoo().getString(); }
子类重写时按需提取需要的Bar字段即可:
@Override protected String doSomething(DoSomethingContext context) { if (Objects.equals(context.getBar().getType(), "something")) { return context.getBar().getString(); } return super.doSomething(context); }
后续如果有新参数需要新增,仅需扩展Context类即可,无需修改所有继承类的方法签名。
方案3:将Bar作为子类固有成员变量注入
适合Bar属于子类B的固有依赖、不会每次调用方法时动态变化的场景:
public class B extends A { private Bar bar; // 构造方法/Setter注入Bar实例 public B(Bar bar) { this.bar = bar; } @Override protected String doSomething(Foo foo) { if (Objects.equals(bar.getType(), "something")) { return bar.getString(); } return super.doSomething(foo); } }
该方案的方法签名最简洁,无多余参数。
内容的提问来源于stack exchange,提问作者Johnny Manzel
相关产品推荐
相关产品推荐

