Должен ли я реализовать интерфейс напрямую или сделать это суперклассом?


14

Есть ли разница между

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

против...

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

Я понимаю, что в обоих случаях класс А в конечном итоге будет соответствовать интерфейсу. Во втором случае 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. Даже если он не предоставляет методы, он может иметь значение. Таких как Собака расширяет, Животные реализуют Ваг. Это не имеет смысла для всех животных, чтобы вилять. Обратите внимание, что этот подход на самом деле не мешает AbstractB предоставлять реализацию.

public class A extends AbstractB
public AbstractB implements C

Я бы использовал этот, если бы я хотел, чтобы все подклассы реализовали интерфейс И это имело бы смысл для всех них. Такие как Beagle расширяет, AbstractDog реализует Wag.

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

Это излишне, но может добавить ясности.


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