У меня есть интерфейс A, для которого я должен предоставить несколько разных реализации. Однако эти реализации имеют общие вспомогательные методы, поэтому Я переместил эти методы в абстрактный базовый класс.
Interface A {
void doX();
}
abstract Class B implements A {
protected void commonY() {
// ...
}
@Override
public abstract void doX();
}
Class C extends B {
@Override
public void doX() {
// ...
}
}
Class D extends B {
@Override
public void doX() {
// ...
}
}
Мой код работает должным образом, но у меня есть несколько вопросов:
Должен ли я объявить абстрактный метод doX () в классе B? Почему нет)?
Должен ли я также явно объявить «реализует A» для классов C и D? Почему нет)?
Нет. Это абстрактный класс - определение интерфейса будет означать, что все подклассы должны будут реализовать эти методы. Другими словами, это избыточно.
Нет, опять же - поскольку ваш суперкласс (абстрактный базовый класс) реализует этот интерфейс, ваши конкретные подклассы будут гарантированно реализовывать этот интерфейс.
Абстрактный класс, реализующий интерфейс, должен реализовывать этот интерфейс. В частности, он должен иметь общедоступный метод для каждого имени метода и сигнатуры, указанных в этом интерфейсе.
Наследование переходное. Вам не нужно писать, что класс C реализует интерфейс A, если класс C является производным от класса B, который реализует интерфейс A. Однако это тоже не сильно повредит.
Хм, наверное, ты прав. Я терял память о Java и о моем текущем опыте работы с C#. В C# абстрактный класс, реализующий интерфейс, требуется для реализации всех методов интерфейса (даже просто помечая их как абстрактные).
Я бы не объявлял doX()
в B
и не добавлял «implements A
» в C
и D
, потому что вы должны не повторяйся.
Абстрактный doX()
в B
ничего не добавляет, поскольку он уже указан в "implements A
". То же самое верно для добавления «implements A
» к C
и D
.
Единственное возможное использование этих пунктов - документация: если вы хотите четко указать, что C
(или D
) - это A
, то вы можете добавить implements
, но вы должны знать, что это действительно не имеет значения. компилятор.
Думаю, лучше было бы сделать так:
Interface A {
void doX();
}
abstract Class B {
protected void commonY() {
// ...
}
}
Class C extends B implements A{
public void doX() {
// ...
}
}
Class D extends B implements A{
public void doX() {
// ...
}
}
Не следует путать интерфейс (сигнатуру методов) с реализацией.
Преимущество этого решения заключается в том, что когда вводится класс X, реализующий Z, но требующий функциональности метода commonY, он может специализироваться на классе B.
Это будет зависеть от использования. Если B является базой для нескольких реализаций A, тогда он должен реализовывать A. То же, что и AbstractList или AbstractCollection.
Я просто добавлю другой вариант.
Превратите абстрактный класс B в класс AUtil, который не реализует A. Для сигнатур методов может потребоваться дополнительный аргумент типа A для работы.
C и D реализуют A и создают экземпляр AUtil внутри. Это позволяет C и D расширять другие классы.
Я бы точно так и поступил. Я категорически против использования наследования ради предоставления методов. Вот для чего нужны статические служебные методы!
Я согласен с JeeBee: подумайте о реализации ваших вспомогательных методов где-нибудь, кроме абстрактного базового класса.
Если ваш вспомогательный метод commonY () существует только в абстрактном базовом классе B, все классы, реализующие интерфейс A, должны будут также расширить базовый класс B, чтобы воспользоваться этой реализацией commonY (). Но вы не всегда можете захотеть расширить класс B.
Кроме того, что, если вы захотите изменить реализацию commonY () в будущем? Затем вы повлияете на множество реализаций интерфейса A. Но если вы не контролируете все эти реализации интерфейса A, вы можете повлиять на их функциональность (плохим образом), не намереваясь этого.
Использование абстрактного базового класса в этой ситуации может просто отнять некоторую гибкость, не давая ничего взамен.
Я не думаю, что абстрактный класс должен реализовывать каждый метод в интерфейсе. Я только что протестировал это, и кажется, что вы можете реализовать интерфейс в абстрактном классе, фактически не объявляя какие-либо методы интерфейса.