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);
    }
}