100% Абстрактный класс vs Интерфейс
Есть ли причина использовать 100% абстрактный класс, а не интерфейс?
Можете ли вы дать мне хороший пример, когда использовать оба, чтобы немного понять концепцию?
Обновление:
100% Абстрактный класс → абстрактный класс с абстрактными методами.
Я заинтересован, если есть различия между php и java в отношении этого аспекта.
Update2:
Даже если я понимаю большинство причин, которые больше меня интересуют концептуальные более чем технические причины.
Ответы
Ответ 1
Если в "100% абстрактном классе" вы подразумеваете "абстрактный класс без каких-либо конкретных методов", я могу придумать причину: видимость.
Вы можете определить абстрактный метод для защиты и, следовательно, не являться частью общедоступного API класса. Однако это кажется странным дизайном.
Еще одна вещь, которая пришла мне на ум, - это то, когда вы ожидаете добавить общую функциональность базовому классу - то есть, если у нее, вероятно, будут какие-то общие методы для всех разработчиков, но эти методы не реализованы.
Другое дело - переменные экземпляра. Вы можете иметь наследуемые переменные экземпляра в абстрактном классе.
Ответ 2
Один случай, когда "100% абстрактный класс" может быть выгодным по интерфейсу, - это места, в которых стабильность API является ключевой проблемой.
Если вы пишете API, где другие люди должны реализовать свой интерфейс, вы должны придерживаться интерфейса. Вы не можете добавить какие-либо методы в интерфейс позже, потому что это сломает всех клиентов (вам придется обойти это, реализуя второй интерфейс и позволяя вашему коду снова проверять использование с проверками instanceof и предоставлять резервную копию).
Если вы осознаете то же самое с классом, вы можете добавить (не абстрактные) методы позже, не нарушая работу клиента.
Ответ 3
Рядом с видимостью, другая причина может заключаться в том, чтобы иметь возможность указать определенный конструктор, который вы хотите реализовать во всех реализациях, или определить определенное свойство. Но в целом, я согласен с Александром в том, что 100% абстрактный класс - не очень хорошая идея. Я бы предпочел интерфейс в большинстве случаев, если не было очень хорошей причины не использовать интерфейс.
Ответ 4
Я лично считаю разницу концептуальной более чем технической. Например, было бы плохой идеей иметь интерфейс под названием "Человек" и реализовать их на мужчинах и женщинах. Было бы разумнее сделать Человека как класс.
Вы можете реализовать несколько интерфейсов, и вы должны видеть интерфейсы в качестве надстроек.
Ответ 5
Я не совсем уверен, как больше ответить на эту концепцию, но на практике я использую интерфейсы по следующим причинам:
- Чтобы указать, что разные классы имеют общий интерфейс: вы можете ими управлять/использовать их одинаково.
- Вы можете реализовать несколько интерфейсов, но только расширить один класс
Причины использования абстрактных классов:
- Обмениваться функциональностью между похожими объектами. Например, Porshe911 может расширить Car, перезаписать несколько методов и сохранить остальные.
- Чтобы написать фреймворки, которые люди могут адаптировать. Например, оставив несколько важных методов нереализованными и написание остальной части класса будет непротиворечивым, если вы реализуете эти несколько методов. Примером может служить класс меню с единственным абстрактным методом getMenuItems()
Ваш пример из 100% абстрактного класса кажется мне бессмысленным. Насколько я вижу, это просто сделает его интерфейсом с добавленным ограничением, что вы можете иметь только один.
Ответ 6
100% Абстрактный класс - это не очень хорошая идея. Для общей структуры дочерних классов используется интерфейс. Для аналогичных классов с одними и теми же методами и не одними и теми же другими лучше использовать абстрактный класс.
Ответ 7
Вот простой пример, который может быть достигнут только интерфейсом.
interface P {
void p();
}
interface Q {
void q();
}
interface R {
void r();
}
class PQR implements P, Q, R {
@Override
public void p() {
System.out.println("P");
}
@Override
public void q() {
System.out.println("Q");
}
@Override
public void r() {
System.out.println("R");
}
}
class A {
public void a(P pRef) {
pRef.p();
}
}
class B {
public void b(Q qRef) {
qRef.q();
}
}
class C {
public void c(R rRef) {
rRef.r();
}
}
public class InterfaceDemo {
public static void main(String[] args) {
P p = new PQR();
A ainvoker = new A();
ainvoker.a(p);
Q q = new PQR();
B binvoker = new B();
binvoker.b(q);
R r = new PQR();
C cinvoker = new C();
cinvoker.c(r);
}
}