如何降低Java抽象类与具体实现类间通过super()产生的耦合
问题场景
现有如下抽象类定义:
public abstract class Foo { protected int var1; protected String var2; protected Foo(int var1, String var2) { this.var1 = var1; this.var2 = var2; } //abstract methods here }
对应具体实现类代码如下:
public class ConcreteFoo1 extends Foo{ public ConcreteFoo1(int var1, String var2) { super(var1, var2); } //methods override }
当前遇到的问题:每次在抽象类中新增实例变量,或是修改抽象类中已有的实例变量时,都需要同步修改所有对应的具体类。需要可行方案,避免这种通过super()传参进行依赖注入产生的耦合问题。
解决方案
有两种常用方案可以解决这个问题,根据字段的必填性选择即可:
方案1:封装公共参数为配置对象
把抽象类所有公共的实例字段统一封装到一个独立的配置类中,抽象类和子类的构造方法都只接收这个配置对象作为参数。后续调整公共字段时,只需要修改配置类和抽象类内部的赋值逻辑,所有子类的构造方法不需要做任何改动。
示例代码:// 统一封装父类公共参数 public class FooConfig { private int var1; private String var2; // 后续新增公共字段直接在此处定义,补全getter/setter即可 public FooConfig(int var1, String var2) { this.var1 = var1; this.var2 = var2; } // getter、setter省略 }修改后的抽象类:
public abstract class Foo { protected int var1; protected String var2; protected Foo(FooConfig config) { this.var1 = config.getVar1(); this.var2 = config.getVar2(); } // 抽象方法 }修改后的子类:
public class ConcreteFoo1 extends Foo{ public ConcreteFoo1(FooConfig config) { super(config); } // 重写方法 }这个方案适合公共字段为实例化必填项的场景,可以保证对象创建完成时状态完整,不会出现缺字段的情况。
方案2:无参构造+Setter/Builder初始化公共字段
给抽象类提供无参构造方法,不在构造阶段强制传入公共字段,而是通过Setter方法或者Builder模式给公共字段赋值。子类不需要显式声明带参构造调用super()传参,默认的无参构造会自动调用父类无参构造,后续父类调整公共字段时子类完全不需要修改代码。
示例代码:public abstract class Foo { protected int var1; protected String var2; // 无参构造,子类可直接隐式调用 protected Foo() {} // 公共字段提供setter方法 public void setVar1(int var1) { this.var1 = var1; } public void setVar2(String var2) { this.var2 = var2; } // 抽象方法 }修改后的子类:
public class ConcreteFoo1 extends Foo{ // 不需要显式声明带参构造,默认无参构造自动调用父类无参构造 // 重写方法 }实例化示例:
ConcreteFoo1 foo = new ConcreteFoo1(); foo.setVar1(1); foo.setVar2("test");如果觉得Setter赋值过于零散,可以给父类实现链式Builder,简化赋值流程。这个方案适合公共字段有默认值、非必填的场景,灵活度更高。
注意:如果抽象类的公共字段是所有子类必须具备的核心属性,不要为了减少代码改动把字段下放到各个子类重复定义,会造成更严重的代码冗余和维护问题。
内容的提问来源于stack exchange,提问作者FrMan
相关产品推荐
相关产品推荐

