Dois-je implémenter une interface directement ou demander à la superclasse de le faire?

14

Y a-t-il une différence entre

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

contre...

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

Je comprends que dans les deux cas, la classe A finira par se conformer à l'interface. Dans le second cas, AbstractBpeut fournir l'implémentation des méthodes d'interface dans C. Est-ce la seule différence?

Si je ne souhaite PAS fournir d'implémentation pour l'une des méthodes d'interface dans AbstractB , quel style dois-je utiliser ? L'utilisation de l'un ou de l'autre a-t-elle un but caché de «documentation»?

c_maker
la source
3
suggestion sur le titre: devrais-je implémenter une interface directement ou faire faire la superclasse
Jeanne Boyarsky

Réponses:

20

Tout dépend si AbstractB implements Csémantiquement. C'est-à-dire si cela a un sens sémantique pour AbstractBêtre implémenté C, alors allez-y.

Si nous prenons des exemples concrets, la différence sémantique devient claire.

Si A = chien, abstrait B = animal, C = IBark

Le seul choix qui a du sens est

class Dog extends Animal implements IBark{

Cela n'a aucun sens, car cela impliquerait que tous les animaux aboient.

class Animal implements IBark{

Les autres différences entrent en jeu si vous avez plus que simplement class Ahérité de AbstractB. Dans # 1, ils n'ont pas besoin d'implémenter C, dans # 2, ils sont tous obligés d'implémenter C.

Karthik T
la source
1
+1 Beaucoup plus clair que ma réponse!
Hand-E-Food
De plus, si l'interface l'était, Heterotrophil semble raisonnable de la mettre en Animalœuvre Heterotroph. Si vous vous attendez à beaucoup d'autres animaux qui aboient et que vous souhaitez les traiter de la même manière, une autre classe BarkingAnimal extends Animal implements IBarkserait la voie à suivre.
scarfridge
@scarfridge En fait, je m'attendrais à ce que l'animal s'étende, Heterotrophmais merci pour votre contribution
Karthik T
2

Le moyen facile de déterminer la relation d'héritage appropriée n'est pas d'examiner les classes elles-mêmes, mais le code qui appelle des méthodes sur ces classes. Quelque part dans votre code, vous avez quelque chose comme AbstractB b = new A();ou otherObject.addAbstractB(this);. Dans les deux cas, vous utiliserez ultérieurement cette AbstractBréférence pour effectuer divers appels de méthode.

Dans cette situation, allez-vous vouloir appeler des méthodes de C? Si oui, alors AbstractBdevrait mettre en œuvre C. Sinon, ça ne devrait pas. Si vous n'avez pas de situations comme celle-là, vous n'avez pas besoin d'héritage et vous devez refactoriser la composition à la place, car elle est beaucoup plus lâche.

Karl Bielefeldt
la source
2

Ce n'est pas un objectif de documentation "caché". Il vous permet de convertir AbstractB et toutes ses sous-classes en C. Il existe en fait trois styles.

public class A extends AbstractB implements C
public class AbstractB

J'utiliserais celui-ci si AbstractB n'a pas implémenté logiquement C. Même s'il ne fournit pas les méthodes, il pourrait avoir un sens. Tels que Dog étend Animal met en œuvre Wag. Il n'est pas logique que tous les animaux remuent. Notez que cette approche n'empêche pas réellement AbstractB de fournir l'implémentation.

public class A extends AbstractB
public AbstractB implements C

J'utiliserais celui-ci si je voulais que toutes les sous-classes implémentent l'interface ET il est logique que toutes le fassent. Tels que Beagle étend AbstractDog implémente Wag.

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

Celui-ci est redondant mais pourrait ajouter de la clarté.

Jeanne Boyarsky
la source
Je pense que "AbstractC" (qui n'existe pas dans la question) dans le 2ème paragraphe devrait être changé en "AbstractB". Je ne peux pas éditer pour le faire car les éditeurs doivent être au moins 6 caractères.
cellepo