Как заставить подклассы установить переменную в Java?

У меня есть класс, который определяет все основные параметры для данного экрана. Отсюда каждый экран в приложении является подклассом этого. Мне нужен каждый экран (то есть подкласс), чтобы установить значение переменной в его реализации (а именно, каждый экран должен определять, какой уровень он имеет в дереве навигации).

Кроме того, в идеале, эта переменная должна быть final когда она установлена в подклассах (я понимаю, что это, вероятно, невозможно).

Каков наилучший способ сделать это? Есть ли способ правильно применить этот тип поведения в Java?

Ответы

Ответ 1

@pst комментарий приводит к этому решению.

Это невозможно сделать с переменной. Но абстрактному классу может потребоваться реализация определенного метода: этот метод может вернуть применимое значение

От объявления функции abstract для установки или возврата переменной вы можете принудительно реализовать любой подкласс.

Далее, функция должна вызываться каждым отдельным подклассом внешнего класса. Это означает, что это должно быть сделано где-то во внешнем классе. Это можно сделать в конструкторе без аргументов внешнего класса, не беспокоясь о подклассах, вызывающих super:

Примечание. Если конструктор явно не вызывает конструктор суперкласса, компилятор Java автоматически вставляет вызов конструктору без аргументов суперкласса. Если у суперкласса нет конструктора без аргументов, вы получите ошибку времени компиляции. У объекта есть такой конструктор, поэтому, если Object является единственным суперклассом, проблем нет. (Java docs: Super)

Исходя из этого, это решение задержит и вернет force переменную, которая будет установлена, если:

  • В суперклассе нет другого конструктора (поэтому супер не может использоваться в подклассе для вызова другого конструктора)
  • Все остальные конструкторы в суперклассе по-прежнему вызывают конструктор по умолчанию внутри

Код:

суперкласса:

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
    }

}

Ответ 2

Вместо того чтобы предписывать экземплярам дочернего класса инициализировать поля, вы можете следовать стратегии компоновки, если ваш родительский конструктор класса принимает параметр, реализующий интерфейс, который предоставляет поля, которые вы хотите инициализировать.

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

interface ConfigFactory {
  Configuration make();
}

Я бы предостерег от требования, чтобы экземпляр подкласса инициализировал конфигурацию, скажем, используя реализацию абстрактного метода. Назначение в конструкторе родительского класса происходит до инициализации экземпляра подкласса, неявно делая правильное вычисление конфигурации статическим.

Если вычисления не являются статичными, вы рискуете получить нулевые ссылки или NullPointerExceptions разработчиками, которые следуют за вами (или вами самими, если ваша память не идеальна). Сделайте это проще для ваших соавторов (и для вас самих) и сделайте ограничения явными.