You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何降低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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 07:42:18