java - 如何在不重复代码的情况下编写子类构造函数?

标签 java oop inheritance

我想在一个抽象父类(super class)的构造函数中调用一个抽象方法generateId(),这个抽象方法依赖于各个子类的一些字段。为清楚起见,请考虑以下代码片段:

抽象类:SuperClass

public abstract class SuperClass {
   protected String id;

   public SuperClass() {
        generateId();
   }

   protected abstract void generateId();
}

子类:Sub1

public class Sub1 extends SuperClass {
   private SomeType fieldSub1;

   public Sub1(SomeType fieldSub1) {
      this.fieldSub1 = fieldSub1;
      super();
   }

   protected void generateId() {
      // Some operations that use fieldSub1
   }
}

子类:Sub2

public class Sub2 extends SuperClass {
   private SomeOtherType fieldSub2;

   public Sub2(SomeOtherType fieldSub2) {
      this.fieldSub2 = fieldSub2;
      super();
   }

   protected void generateId() {
      // Some operations that use fieldSub2
   }
}

但是,子类构造函数将不起作用,因为 super(); 必须是构造函数中的第一条语句。

OTOH,如果我将 super(); 作为子类构造函数中的第一条语句,那么我将无法在 父类(super class)。因为 generateId() 在子类中使用字段,所以这些字段必须在使用前进行初始化。

在我看来,“解决”这个问题的唯一方法是:在父类(super class)中删除对 generateId() 的调用。在每个 子类的构造函数末尾调用generateId()。但这会导致代码重复。

那么有没有什么办法可以在不重复我的代码的情况下解决这个问题呢? (也就是说,在 each 子类的构造函数末尾不调用 generateId()?)

最佳答案

正如@GuillaumeDarmont 指出的那样,在构造中使用可覆盖的方法是不好的做法。

你想让父类(super class) id 被子类初始化,所以改变构造函数:

public abstract class SuperClass {
    protected String id;

    public SuperClass(String id) {
        this.id = id;
    }
}

此外,您可能希望将 generateId() 更改为静态方法,因为您无法在调用父类(super class)构造函数之前引用 this:

public class Sub1 extends SuperClass {
    private SomeType fieldSub1;

    public Sub1(SomeType fieldSub1) {
        super(generateId(fieldSub1));
        this.fieldSub1 = fieldSub1;
    }

    private static String generateId(SomeType fieldSub1) {
        // Some operations that use fieldSub1
    }
}

编辑:因为 SuperClass 不知道如何计算 id,但你想强制它有一个 id,你的选项是上面的解决方案。另一种选择是:

public abstract class SuperClass {
    private String id;

    public String getId() {
        if (id == null) { id = generateId(); }
        return id;
    }
    protected abstract String generateId();
}


public class Sub1 extends SuperClass {
    private SomeType fieldSub1;

    public Sub1(SomeType fieldSub1) {
        this.fieldSub1 = fieldSub1;
    }

    @Override protected String generateId() {
        // Some operations that use fieldSub1
    }
}

这两种解决方案的区别在于何时将计算id:在对象初始化时,或者第一次请求id 时。这就是 @Turing85 正在讨论的内容。

关于java - 如何在不重复代码的情况下编写子类构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34612533/

相关文章:

java - iText:为什么无序 html 项目符号列表的最后一项没有显示在我的 PDF 上?

python - Python 中的 "public"或 "private"属性?什么是最好的方法?

php - 继承和可见性 - PHP

Java 程序在 "for"循环后卡住

java - SimpleDateFormat 没有正确处理 DD

java - 使用 MultiThreadedHttpConnectionManager 为同一个 httpclient 设置不同的套接字超时

hibernate - 使用 ColdFusion ORM 缺乏变量的使用。实例范围?

list - 为什么 Haskell 允许 Shape 列表,但不允许 Square 或 Circle 或 Triangle 列表

python - 继承自 defaultdict 和 OrderedDict

C#接口(interface)和继承问题