OOP: Quelles sont les situations dans lesquelles la conception basée sur les classes est meilleure que celle basée sur les interfaces?

9

Je lisais le site Web de JDOM .

Pourquoi l'API JDOM est-elle définie en termes de classes concrètes plutôt qu'en termes d'interfaces?

Jason Hunter résume les arguments contre une API basée sur interface pour JDOM:

Avec les interfaces, tout devient une usine, les éléments doivent être «importés» dans de nouveaux documents au lieu d'être simplement ajoutés, des fonctionnalités telles que la sérialisation à long terme ne peuvent pas être garanties et la liste continue.

Nous avons commencé avec des interfaces en fait. Au cours de notre examen préalable à la publication à certains de nos pairs, nous avons reçu les commentaires que nous devrions essayer des classes concrètes. Nous l'avons fait, et le design était bien meilleur pour cela.

Je suis designer débutant. Tous les conseils dont j'ai entendu parler jusqu'à présent déconseillent l' utilisation de la conception avec des classes concrètes.

L'utilisation de classes concrètes peut être appropriée à certains endroits. Existe-t-il des problèmes de classe courants pour lesquels l'utilisation de classes concrètes dans la conception est acceptable?

Vinoth Kumar CM
la source
Vous voudrez peut-être y jeter un œil: javaworld.com/javaworld/jw-09-2001/jw-0921-interface.html
NoChance
Vous pouvez également consulter la série "Limitez vos abstractions": ayende.com/blog/153889/…
henginy
"Nous l'avons fait, et le design était bien meilleur pour cela." - comment était-ce mieux?
CodeART

Réponses:

5
  • L'héritage crée des dépendances sur l'implémentation , ce qui pourrait être un gros problème de maintenabilité. Le corollaire de ceci est que vous pouvez utiliser en toute sécurité l'héritage et les classes concrètes lorsque vous traitez avec un objet de transfert de données , qui par définition ne contient presque aucune implémentation. Vous pouvez également utiliser l'héritage de classes concrètes lorsque vous souhaitez cette dépendance. Vous voudrez peut-être utiliser une classe abstraite contenant les méthodes courantes (généralement des fonctions utilitaires) en haut de la hiérarchie dans cette situation.
  • Lorsque vous utilisez une hiérarchie de classe concrète, n'oubliez pas d'appliquer le principe de substitution Liskov .
  • Il n'y a aucun problème à utiliser des classes concrètes pour les clients (c'est-à-dire des classes qui utilisent, pas des classes qui sont utilisées).
  • À mon humble avis, vous pouvez utiliser des classes concrètes jusqu'à ce qu'il y ait des choses à changer. Le principe ouvert / fermé vous dirait d'utiliser des interfaces pour éviter le couplage, mais en ce qui concerne le principe vous n'en aurez pas besoin, vous pourriez envisager d'utiliser des classes concrètes jusqu'au moment où vous devez changer quelque chose dans l'implémentation. Le problème est que vous devrez changer chaque client de vos classes la première fois que quelque chose change quelque part. Bien que vous n'ayez qu'un seul outil possible pour faire quelque chose, vous pouvez utiliser des classes concrètes IMO.

[MODIFIER] Le site Web de JDOM prend java.io.File comme exemple, mais il s'agit certainement d'une conception basée sur une interface car on peut manipuler une instance de java.io.File comme s'il ne s'agissait que d'un Serializable. Dans cette situation, seuls les «créateurs» sauraient la classe concrète

Matthias Jouan
la source
Il existe deux définitions contradictoires de "valeur objet" flottant autour. Le vôtre semble être le moins courant, également appelé «objet de transfert de données».
Michael Borgwardt
@MichaelBorgwardt Thx pour l'avoir signalé car je ne voulais pas seulement dire "objet de transfert de données": je modifie ma réponse
Matthias Jouan
1
LSP est important pour toute relation de sous-typage, la mise en œuvre d'interface ainsi que l'héritage.
2

Depuis le site JDOM:

Jason (Hunter) a fondé le projet JDOM au début de 2000 avec Brett McLaughlin

Autrement dit, au moment où Java 1.3 était introduit. Il n'y avait rien en termes de maturité en matière de développement Java - les développeurs les plus expérimentés n'avaient au mieux que 4 ans d'utilisation de Java. Il n'y avait pas de conteneurs IoC largement utilisés, pas d'Hibernate. Apache Struts venait juste de commencer.

Tout cela pour dire que Jason et Brett avaient tout simplement tort. Beaucoup de gens ne l'ont pas encore "compris". S'ils avaient des antécédents en C ++, eh bien, vous n'aviez pas besoin d'interfaces en C ++ (eh bien, ils étaient là en C ++, mais vous n'en aviez pas vraiment besoin, non?), Pourquoi diable les utiliser en Java? Eh bien, il y a beaucoup de bonnes raisons vers lesquelles d'autres peuvent vous diriger.

Ils avaient vraiment tort

tout ce qui peut être fait avec des interfaces peut être fait avec un sous-classement

Java ne permet pas l'héritage multiple de classes, mais il permet l'implémentation de plusieurs interfaces. Cela peut faire une réelle différence.

Matthew Flynn
la source
2

N'oubliez pas, tout d'abord, que dans le développement de logiciels, il existe plusieurs façons de résoudre un problème, et si un développeur utilise une technique différente de la vôtre, cela ne signifie pas qu'il a tort.

L'un de ces cas est celui des "interfaces" par rapport aux "classes" (de base). Il existe des situations où le même objectif peut être atteint avec les deux techniques.

Pour compliquer les choses, il y a plusieurs utilisations des interfaces, juste pour mentionner:

  • l'une consiste à concevoir un «contrat» ou une «spécification» sans «mise en œuvre»
  • autre pour ajouter une fonction à une classe ou hiérarchie de classes existante
  • complémentaire au précédent, pour permettre un accès partagé entre différents objets, technologies, exemple: Enterprise Beans, CORBA, COM, WebServices
  • pour émuler l'héritage multiple

Votre question s'applique au premier point.

Lorsque vous souhaitez développer une hiérarchie de classes, pas seulement une seule classe, et que plusieurs classes sont destinées à partager certaines fonctionnalités spécifiques, vous pouvez commencer par une classe de base, même si cela peut être fait avec une interface.

Et, laissez les interfaces pour les autres scénarios.

Les bibliothèques de widgets (contrôles) en sont un bon exemple.

Je suggère, qui jette un œil à d'autres langages de programmation, comment utilisent-ils les interfaces et les classes comme: PHP, Delphi (Object Pascal), C #.

À votre santé.

umlcat
la source
0

Vous voulez généralement une interface pour tout ce qui est passé en tant que paramètre ou retourné, essentiellement afin de pouvoir dissocier la classe de ses dépendances.

Donc, si nous recherchons une classe, nous ne passons jamais normalement à l'esprit. Je ne suis pas développeur Java, mais certainement dans d'autres langages similaires, je ne pense pas avoir vu d'interfaces définies pour les exceptions.

jk.
la source
0

Les règles de conception d'API sont vraiment une chose spécifique. Je ne suis pas sûr que vous devriez conclure quoi que ce soit de cette FAQ en ce qui concerne la façon dont vous devez concevoir votre code au jour le jour.

Pour votre code normal, il est toujours vrai que vous utiliserez l'héritage d'interface ou de classe abstraite beaucoup plus souvent que l'héritage vanilla IMO.

Pour bien comprendre cette règle, vous devez vous placer non pas du point de vue d'une classe dérivée par rapport à sa superclasse, mais du point de vue d'un objet qui a une dépendance à un autre objet. Il est presque toujours préférable de dépendre d'une abstraction plutôt que d'une implémentation concrète car cela vous permet d'accepter toute une série de classes différentes comme dépendances, en vous appuyant sur leur contrat et non sur leurs détails d'implémentation.

La première utilisation pour ce qui est souvent dans les tests unitaires - si vous voulez vraiment l' unité test de votre classe dans un isolement complet, vous le faites contre les implémentations de faux de vos dépendances qui sont différentes des implémentations réelles qui seront utilisées dans la production.

guillaume31
la source