Confusion d’interfaces et de classes abstraites en Java avec exemples

J’ai du mal à comprendre quand utiliser une interface par opposition à une classe abstraite et vice versa. En outre, je suis confus quand étendre une interface avec une autre interface. Désolé pour le long post, mais c’est très déroutant.

Créer des formes semble être un sharepoint départ populaire. Disons que nous voulons un moyen de modéliser des formes 2D. Nous soaps que chaque forme aura une zone. Quelle serait la différence entre les deux implémentations suivantes:

avec interfaces:

public interface Shape { public double area(); } public class Square implements Shape{ private int length = 5; public Square(){...} public double area() return length * length; } } 

avec classe abstraite:

 abstract class Shape { abstract public double area(); } public class Square extends Shape { private length = 5; public Square(){...} public double area(){ return length * length; } 

Je comprends que les classes abstraites vous permettent de définir des variables d’instance et vous permettent d’implémenter des méthodes alors qu’une interface ne peut pas faire cela. Mais dans ce cas, il semble que ces deux implémentations soient identiques. Donc, utiliser n’importe qui est bien?

Mais disons maintenant que nous voulons décrire différents types de sortingangles. Nous pouvons avoir des sortingangles isocèles, aigus et à angle droit. Pour moi, il est logique d’utiliser l’inheritance de classe dans ce cas. Utilisation de la définition «IS-A»: un sortingangle rectangle «IS-A». Un sortingangle “IS-A” forme. En outre, une classe abstraite doit définir les comportements et les atsortingbuts communs à toutes les sous-classes, ce qui est parfait:

avec classe abstraite

 abstract Triangle extends Shape { private final int sides = 3; } class RightTriangle extends Triangle { private int base = 4; private int height = 5; public RightTriangle(){...} public double area() { return .5 * base * height } } 

Nous pouvons également le faire avec des interfaces, avec des interfaces Triangle et Shape. Cependant, contrairement à l’inheritance de classe (utilisation de la relation ‘IS-A’ pour définir ce qui devrait être une sous-classe), je ne sais pas comment utiliser une interface. Je vois deux façons:

Première manière:

  public interface Triangle { public final int sides = 3; } public class RightTriangle implements Triangle, Shape { private int base = 4; private int height = 5; public RightTriangle(){} public double area(){ return .5 * height * base; } } 

Deuxième manière:

 public interface Triangle extends Shape { public final int sides = 3; } public class RightTriangle implements Triangle { .... public double area(){ return .5 * height * base; } } 

Il me semble que ces deux méthodes fonctionnent. Mais quand utiliseriez-vous un moyen par rapport à l’autre? Et y-a-t-il des avantages à utiliser des interfaces sur des classes abstraites pour représenter différents sortingangles? Même si nous avons compliqué la description d’une forme, l’utilisation de l’interface vs classe abstraite semble toujours équivalente.

Un composant essentiel des interfaces est la possibilité de définir des comportements pouvant être partagés entre des classes non liées. Une interface Flyable serait donc présente dans les classes Avion ainsi que dans Bird. Donc, dans ce cas, il est clair qu’une approche d’interface est préférable.

En outre, pour tirer parti de l’interface déroutante qui étend une autre interface: Quand faut-il ignorer la relation ‘IS-A’ lorsqu’on décide de ce qui devrait être une interface? Prenez cet exemple: LINK .

Pourquoi “VeryBadVampire” devrait-il être une classe et “Vampire” une interface? Un «VeryBadVampire» est un «vampire», je pense donc qu’un «vampire» devrait être une super-classe (peut-être une classe abstraite). Une classe «vampire» peut mettre en œuvre «Lethal» pour conserver son comportement mortel. En outre, un «vampire» est un «monstre», donc «monstre» devrait également être une classe. Une classe ‘Vampire’ peut également implémenter une interface appelée ‘Dangerous’ pour conserver son comportement dangereux. Si nous souhaitons créer un nouveau monstre appelé «BigRat» dangereux mais non fatal, nous pouvons créer une classe «BigRat» qui étend «Monster» et implémente «Dangerous».

Ce qui précède n’atteindrait-il pas le même résultat que l’utilisation de «Vampire» comme interface (décrite dans le lien)? La seule différence que je vois est que l’utilisation de l’inheritance de classe et la préservation de la relation ‘IS-A’ dissipe beaucoup de confusion. Pourtant, cela n’est pas suivi. Quel est l’avantage de le faire?

Même si vous vouliez qu’un monstre partage le comportement vampirique, vous pouvez toujours redéfinir la manière dont les objects sont représentés. Si nous voulions un nouveau type de monstre de vampire appelé «VeryMildVampire» et si nous voulions créer un monstre ressemblant à un vampire appelé «Chupacabra», nous pouvons le faire:

La classe ‘Vampire’ étend ‘Monster’ et implémente ‘Dangerous’, ‘Lethal’, ‘BloodSuckable’
La classe ‘VeryMildVampire’ étend la classe ‘Vampire’
La classe ‘Chupacabra’ étend ‘Monster’ implémente ‘BloodSuckable’

Mais on peut aussi faire ça:

‘VeryMildVampire’ prolonge ‘Monster’ implémente Dangerous, Lethal, Vampiric
«Chupacabra» étend «Monster» implémente Dangerous, Vampiric

La deuxième manière crée ici une interface «vampirique» afin que nous puissions définir plus facilement un monstre associé plutôt que de créer un ensemble d’interfaces définissant les comportements vampiriques (comme dans le premier exemple). Mais cela rompt la relation IS-A. Donc je suis confus …

N’oubliez pas le concept de base lorsque vous utilisez des classes abstraites ou des interfaces.

Les classes abstraites sont utilisées lorsque la classe à étendue est plus étroitement couplée à la classe la mettant en œuvre, c’est-à-dire lorsque les deux ont une relation parent-enfant.

Par exemple:

  abstract class Dog {} class Breed1 extends Dog {} class Breed2 extends Dog {} 

Breed1 et Breed2 sont les deux types de chien et ont un comportement commun en tant que chien.

Alors qu’une interface est utilisée lorsque la classe d’implémentation a une fonctionnalité qu’elle peut prendre de la classe à implémenter.

  interface Animal { void eat(); void noise(); } class Tiger implements Animal {} class Dog implements Animal {} 

Tiger et le Dog sont deux catégories différentes, mais les deux mangent et font des bruits, qui sont différents. Donc, ils peuvent utiliser manger et le bruit de Animal .

Utilisez une classe abstraite lorsque vous souhaitez qu’une ou plusieurs méthodes ne soient pas abstraites.

Si vous voulez garder tout abstrait, utilisez une interface.

C’est la question qui se posera lors de la conception de hiérarchies de classes peu complexes. Mais généralement, il y a peu de choses que vous devez savoir lorsque vous utilisez des classes abstraites et des interfaces

Classe abstraite

  • Vous permet d’exploiter la puissance de l’utilisation de constructeurs et du remplacement de constructeur
  • Restreindre la classe ayant plusieurs inheritances (particulièrement utile si vous concevez une API compliquée)
  • Variables d’instance et implémentations de méthodes
  • Tirer parti de la puissance du super appel de méthode (Utilisez super pour appeler l’implémentation de la classe abstraite parent)

Interface

  • Active l’inheritance multiple – vous pouvez implémenter un nombre n d’interfaces
  • Permet de ne représenter que des méthodes conceptuelles (pas de corps de méthode)

En règle générale, utilisez les interfaces pour la clause ‘-able’ (comme dans la fonctionnalité). Par exemple:-

  1. Runnable
  2. Observable

Utilisez des classes abstraites pour quelque chose comme is-a (format d’évolution). Par exemple:-

  1. Number
  2. Graphics

Mais des règles ssortingctes ne sont pas faciles à créer. J’espère que cela t’aides

Vous avez pas mal de questions ici. Mais je pense que fondamentalement vous posez des questions sur l’interface et la classe abstraite.

Avec les interfaces, vous pouvez avoir des classes qui implémentent plusieurs interfaces. Cependant, l’interface n’est pas durable si vous souhaitez l’utiliser comme API. Une fois l’interface publiée, il est difficile de modifier l’interface car cela va casser les codes d’autres personnes.

Avec une classe abstraite, vous ne pouvez étendre qu’une classe. Cependant, la classe abstraite est durable pour l’API car vous pouvez toujours modifier les versions ultérieures sans endommager le code des autres personnes. De même, avec la classe abstraite, vous pouvez avoir une implémentation prédéfinie. Par exemple, dans votre exemple Triangle, pour une classe abstraite, vous pouvez avoir une méthode countEdges () qui renvoie 3 par défaut.

C’est une question qui revient très souvent, mais il n’y a pas une seule réponse “juste” qui plaira à tout le monde.

Les classes représentent les relations is-a et les interfaces représentent un comportement positif. Je vais habituellement par quelques règles empiriques:

  • Tenez-vous en à une classe (abstraite / concrète) à moins d’être certain d’avoir besoin d’une interface.
  • Si vous utilisez des interfaces, coupez-les en fonctionnalités très spécifiques. Si une interface contient plus que quelques méthodes, vous le faites mal.

En outre, la plupart des exemples de formes et de personnes (ou même de vampires!) Sont généralement de mauvais exemples de modèles du monde réel. La “bonne” réponse dépend de ce que votre application nécessite. Par exemple, vous avez mentionné:

 class Vampire extends Monster implements Dangerous, Lethal, BloodSuckable 

Votre application a-t-elle vraiment besoin de toutes ces interfaces? Combien y a-t-il de types de Monster différents? Avez-vous des classes autres que Vampire qui implémentent BloodSuckable ?

Essayez de ne pas trop généraliser et d’extraire des interfaces quand vous n’en avez pas besoin. Cela revient à la règle de base: restz avec une classe simple à moins que votre cas d’utilisation ne nécessite une interface.

C’est une bonne question. Il y a beaucoup de bonnes et de mauvaises réponses à cette question. La question typique est: quelle est la différence entre une classe abstraite et une interface? Permet de voir où vous utilisez des classes abstraites et où vous utilisez une interface.

Où utiliser les classes abstraites: En termes de POO, s’il existe une hiérarchie d’inheritance, vous devez utiliser une classe abstraite pour modéliser votre conception.
entrer la description de l'image ici

Où utiliser les interfaces: Lorsque vous devez connecter différents contrats (classes non liées) à l’aide d’un contrat commun, vous devez utiliser une interface. Prenons le cadre de la collection comme exemple. entrer la description de l'image ici

Les files d’attente, listes et ensembles ont des structures différentes de celles de leur implémentation.Mais ils partagent néanmoins certains comportements communs tels que add (), remove (). Nous pouvons donc créer une interface appelée Collection et nous avons déclaré des comportements communs dans l’interface. Comme vous le voyez, ArrayList implémente tous les comportements des interfaces List et RandomAccess. Nous pouvons ainsi facilement append de nouveaux contrats sans modifier la logique existante. Ceci s’appelle “coder à une interface”.

Votre exemple de forme est bon. Je le regarde de cette façon:

Vous n’avez des classes abstraites que lorsque vous avez des méthodes ou des variables membres partagées. Pour votre exemple pour Shape vous n’avez qu’une seule méthode, non implémentée. Dans ce cas, utilisez toujours une interface.

Dites que vous aviez une classe d’ Animal . Chaque animal garde la trace du nombre de membres qu’il possède.

 public abstract class Animal { private int limbs; public Animal(int limbs) { this.limbs = limbs; } public int getLimbCount() { return this.limbs; } public abstract Ssortingng makeNoise(); } 

Comme nous devons suivre le nombre de membres de chaque animal, il est logique d’avoir la variable membre dans la superclasse. Mais chaque animal fait un type de bruit différent.

Nous devons donc en faire une classe abstraite car nous avons des variables membres et des méthodes implémentées ainsi que des méthodes abstraites.

Pour votre deuxième question, vous devez vous poser la question suivante.

Un sortingangle sera-t-il toujours une forme?

Si tel est le cas, vous devez disposer d’une extension Triangle à partir de l’interface Shape.

En conclusion, avec votre premier ensemble d’exemples de code, choisissez l’interface. Avec le dernier ensemble, choisissez la deuxième façon.