В Scala я записал бы абстрактный класс с абстрактным атрибутом path
:
abstract class Base {
val path: String
}
class Sub extends Base {
override val path = "/demo/"
}
Java не знает, что краткий обзор приписывает и интересно, каков был бы лучший способ работать вокруг этого ограничения.
Мои идеи:
a) параметр конструктора
abstract class Base {
protected String path;
protected Base(String path) {
this.path = path;
}
}
class Sub extends Base {
public Sub() {
super("/demo/");
}
}
b) абстрактный метод
abstract class Base { // could be an interface too
abstract String getPath();
}
class Sub extends Base {
public String getPath() {
return "/demo/";
}
}
Какой Вы любите лучше? Другие идеи?
Я склонен использовать конструктора, так как значение пути не должно быть вычислено во времени выполнения.
То, что Scala делает внутренне, вы описываете как метод B.
Возьмем следующий пример класса:
abstract class Test{
val path: String
}
Когда вы компилируете это с помощью scalac, он сгенерирует абстрактный класс Java с абстрактным методом с именем attr, который возвращает String. Причина, по которой это может произойти, заключается в том, что val является постоянным и поэтому может эмулироваться только геттером, а не сеттером. Поэтому, если вы хотите получить доступ к этому классу из Java, вы можете просто переопределить абстрактный метод получения.
Это эквивалент класса Java, который будет создан (вывод javap):
public abstract class Test extends java.lang.Object implements scala.ScalaObject{
public abstract java.lang.String path();
public Test();
}
Я бы выбрал вариант b, потому что если по какой-либо причине путь зависит от других атрибутов, то устанавливать атрибут в суперклассе каждый раз, когда изменяется другой атрибут. Если вам нужно реализовать геттер, тогда нет проблем. Я не могу придумать ни одного конкретного случая, когда вариант а был бы более применим .
Если путь
никогда не изменится, я бы выбрал вариант а, в противном случае я бы выбрал вариант б.
Другой аспект заключается в том, что значение path
может быть недоступно во время построения. В этом случае вариант а как бы исключен. Однако, по сравнению с вашим кодом Scala, кажется, что путь
доступен во время создания.
Эквивалент B , поскольку значения фиксированы.
Опция A получает путь в конструкторе, и это значение может быть вычислено во время выполнения, что не соответствует классу Sub
в примере scala.
Вы можете попробовать создать защищенный
метод для установки значения переменной. Вызывается только из классов в одном пакете.
Вероятно, подойдет любой из них - параметр конструктора, вероятно, проще, если никогда не будет никаких вычислений (в этом случае вы, возможно, захотите сделать поле конечным, что даст дополнительное преимущество в том, что оно будет установлено любыми другими конструкторами, которые могут быть добавлены позже); в то время как абстрактный метод дает вам больше свободы для изменений в будущем.
Вы также можете объединить эти два метода, установить приватное поле в конструкторе и предоставить конкретную (но не окончательную) реализацию геттера, который обращается к нему.