Чи потрібно реалізовувати інтерфейс безпосередньо або дозволити суперклас це робити?


14

Чи є різниця між

public class A extends AbstractB implements C
{...}

проти...

public class A extends AbstractB
{...}
abstract class AbstractB implements C
{...}

Я розумію, що в обох випадках клас A в кінцевому підсумку відповідає інтерфейсу. У другому випадку AbstractBможна забезпечити реалізацію методів інтерфейсу в C. Це єдина різниця?

Якщо я не хочу , щоб забезпечити реалізацію будь-якого з методів інтерфейсу в AbstractB , який стиль я повинен використовувати ? Чи використовує те чи інше приховане призначення «документації»?


3
пропозиція щодо назви: чи слід безпосередньо реалізовувати інтерфейс чи дозволити суперклас це зробити
Жанна Боярський

Відповіді:


20

Все залежить від того, чи AbstractB implements Cсемантично. Тобто, якщо це має сенс семантично для AbstractBреалізації C, то перейдіть до цього.

Якщо взяти конкретні приклади, смислова різниця стає зрозумілою.

Якщо A = собака, AbstractB = тварина, C = IBark

Єдиний вибір, який має сенс

class Dog extends Animal implements IBark{

Це не має сенсу, оскільки це означає, що всі тварини гавкають.

class Animal implements IBark{

Інші відмінності грають, якщо ви маєте більше, ніж просто class Aуспадковувати AbstractB. У №1 їм не потрібно впроваджувати C, у №2 всі вони змушені реалізувати C.


1
+1 Набагато чіткіше моєї відповіді!
Hand-E-Food

Крім того, якщо інтерфейс, Heterotrophздавалося, розумно зробити його Animalреалізацією Heterotroph. Якщо ви очікуєте багато інших гавкітних тварин і хочете поводитися з ними так само, BarkingAnimal extends Animal implements IBarkяк іти, буде інший клас .
хустка

@scarfridge Насправді я б очікував, що тварина пошириться, Heterotrophале дякую за ваш внесок
Karthik T

2

Найпростіший спосіб визначення належних відносин успадкування - це не дивитись на самі класи, а на код, який викликає методи цих класів. Десь у коді у вас є щось на кшталт AbstractB b = new A();або otherObject.addAbstractB(this);. У будь-якому випадку, ви пізніше використовуєте це AbstractBпосилання для здійснення різних дзвінків методів.

У цій ситуації ви хочете викликати методи C? Якщо так, то AbstractBслід реалізувати C. Якщо ні, то не повинно. Якщо у вас немає подібних ситуацій, то вам не потрібно спадкування, і ви повинні рефактор використовувати склад замість цього, оскільки він набагато втрачає більше.


2

Це не "прихована" мета документації. Це дозволяє викидати AbstractB і всі його підкласи до C. Є насправді три стилі.

public class A extends AbstractB implements C
public class AbstractB

Я б скористався цим, якщо AbstractB не реалізував логічно C. Навіть якщо він не надає методи, це може мати значення. Такі як Dog розширює Animal реалізує Wag. Немає сенсу ваг для всіх тварин. Зауважимо, що такий підхід насправді не виключає надання контенту AbstractB.

public class A extends AbstractB
public AbstractB implements C

Я б скористався цим, якби хотів, щоб усі підкласи реалізовували інтерфейс І для цього вони мають сенс. Такі як Бігль розширює AbstractDog реалізує Wag.

public class A extends AbstractB implements C
public class AbstractB implements C

Це зайве, але може додати ясності.


Я вважаю, що "абстракціонізм" (якого немає у питанні) у другому абзаці має бути змінено на "АнотаціяБ". Я не можу редагувати це, оскільки редакторів повинно бути не менше 6 символів.
cellepo
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.