27

我有一个类,它定义了给定屏幕的所有基本参数。从这里开始,应用程序中的每个屏幕都是它的子类。我需要每个屏幕(即子类)在其实现中设置变量的值(即,每个屏幕必须定义它在导航树中的级别)。

此外,理想情况下,这个变量应该是final在子类中设置的时候(我意识到这可能是不可能的)。

解决此问题的最佳方法是什么?有没有办法在 Java 中正确执行这种类型的行为?

4

3 回答 3

37

@pst 的评论导致了这个解决方案。

这不能用变量来完成。但是抽象类可以要求实现一个特定的方法:这个方法可以返回适用的值

从声明abstract函数到设置或返回变量,您可以强制任何子类正确实现它。

接下来,必须由外部类的每个子类调用该函数。这意味着它必须在外部类的某个地方完成。这可以在外部类的无参数构造函数中完成,而不必担心子类调用super

注意:如果构造函数没有显式调用超类构造函数,Java 编译器会自动插入对超类的无参数构造函数的调用。如果超类没有无参数构造函数,则会出现编译时错误。Object 确实有这样的构造函数,所以如果 Object 是唯一的超类,则没有问题。 (Java 文档:超级)

基于此,此解决方案将保持并正确强制设置变量,只要:

  1. 在超类中没有创建其他构造函数(因此不能在子类中使用 super 来调用不同的构造函数)
  2. 超类中的所有其他构造函数仍然在内部调用默认构造函数

编码:

超类:

public abstract class SuperClass {
    // Variable all inner classes must set
    static int myVar = 0;

    public SuperClass() {
        myVar = giveValue();
    }

    public abstract int giveValue();
}

子类:

public class SubClass extends SuperClass {

    @Override
    public int giveValue() {
        return 5; // individual value for the subclass
    }

}
于 2013-02-22T03:04:08.193 回答
13

与其强制子类实例初始化字段,不如遵循组合策略,让父类构造函数采用实现接口的参数,该接口提供您希望初始化的字段。

class Screen {
  final Configuration config;
  Screen(Configuration config) {
    this.config = config;
  }
  // or
  Screen(ConfigFactory configFactory) {
    this.config = configFactory.make();
  }
}

interface ConfigFactory {
  Configuration make();
}

我会告诫不要要求子类实例初始化配置,比如使用抽象方法实现。父类构造函数中的赋值发生在子类实例初始化之前,隐式地使配置的正确计算成为静态。

如果计算不是静态的,您可能会冒空引用或 NullPointerExceptions 被跟随您的开发人员(或者您自己,如果您的内存不够完美)。让你的合作者(和你自己)更容易,并使约束明确。

于 2013-02-22T02:23:56.443 回答
3

正如@Ketan 在@BT 的回答中提到的那样,从构造函数调用可覆盖的方法并不是特别好的做法(https://help.semmle.com/wiki/display/JAVA/Non-final+method+invocation+in +构造函数

避免此问题的一种方法是为该字段设置一个抽象的(受保护的)吸气剂。因此超类不再具有该字段,但仍然可以在超类中使用 getter 访问它。每个子类都必须声明该字段,因为它必须覆盖抽象 getter。

超类:

public abstract class SuperClass {

  public SuperClass() {}

  protected abstract int getMyVar();

  public void functionUsingMyVar(){
     int a = 12 + getMyVar();
  }
}

子类1:

public class SubClass1 extends SuperClass {

  private int myVar;

  public SubClass1() {
     super();
     myVar = 1;
  }

  @Override
  protected int getMyVar(){
     return myVar;
  }

}

子类2:

 public class SubClass2 extends SuperClass {

  private int myVar;

  public SubClass2() {
     super();
     myVar = 1;
  }

  @Override
  protected int getMyVar(){
     return myVar;
  }

}

而不是超类(其中 giveValue() 是可覆盖的并在构造函数中调用):

public abstract class SuperClass {

  private int myVar;

  public SuperClass() {
     myVar = giveValue();
  }

  protected abstract int giveValue();

  public void functionUsingMyVar(){
     int a = 12 + myVar;
  }
}
于 2019-11-15T13:54:14.573 回答