Les interfaces sont-elles un mauvais patron de conception ?

Bon, je vais pas faire de mystère, j’ai déjà eu l’occasion de dénigrer le principe des interfaces dans de précédents articles donc autant répondre à la question tout de suite : oui, je pense que les interfaces en POO sont une mauvaise pratique. Mais pour pouvoir affirmer une telle chose, il faut pouvoir l’expliquer. Sur ce sujet, mes notes sur la POO constituent une bonne introduction de mon propos, je pense. Alors commençons tout de suite avec le vif du sujet.

L’idée de départ derrière les interfaces

La première formalisation concrète de la programmation orientée objets apparaît avec les travaux d’Alan Kay et son langage de programmation SmallTalk. Une des caractéristiques de la POO est le principe d’objets et d’héritage entre objets. L’héritage est une notion simple qui consiste à dire qu’un objet va en étendre un autre et donc hériter implicitement de ses caractéristiques (variables et méthodes) sans rien avoir à préciser de plus. Le SmallTalk ne propose, à sa création, qu’un héritage simple. C’est le C++ qui va proposer le premier un mécanisme d’héritage multiple. Il est alors possible de créer un objet qui peut en étendre plusieurs autres, parallèlement. Mais l’héritage multiple pose un gros soucis nommé le problème du diamant. Ce problème est simple : si un objet hérite de deux objets différents mais proposant chacun une méthode avec exactement la même signature mais chacun une implémentation différente, quelle implémentation doit prévaloir ? Java va proposer une solution radicale à ce problème en supprimant la possibilité de faire de l’héritage multiple.

Cependant, il y a des cas d’utilisation très concrets dans lesquels il est nécessaire de pouvoir manipuler un objet de différentes manières. Le cas le plus courant se retrouve dans la conception d’interfaces graphiques : tout objet qui représente un élément qui se dessine à l’écran doit pouvoir se manipuler comme un objet qui se dessine à l’écran et donc pouvoir être stocké dans une liste d’objets qui se dessinent à l’écran. Mais d’un autre côté, les objets qui se dessinent à l’écran n’ont pas tous la même nature. Les boutons doivent pouvoir se manipuler comme des éléments cliquables et les labels, pas. Comment permettre alors de faire de l’héritage multiple sans faire d’héritage multiple ? La réponse de Java sera les interfaces.

Les interfaces sont des sortes de classes bridées. Elles ne peuvent être instanciées ni déclarer d’implémentation de méthodes. Tout ce que peut contenir une interface est donc des variables statiques et des signatures de méthode. De fait, l’héritage en diamant est résolu. On permet que l’objet puisse être maniplulé comme un objet d’un certain type, mais ne déclarer aucune implémentation supprime les problèmes d’ambiguités. On s’assure qu’il n’existe qu’une seule hiérarchie d’héritage donc l’implémentation qui prévaut est soit celle de l’objet, soit celle de sont parent, soit celle de son grand-parent, et ainsi de suite, récursivement, jusqu’au parent premier. C’est alors au développeur de fournir une implémentation pour toutes les méthodes déclarées par l’interface.

Là apparaît la première limitation : les interfaces ne peuvent pas être trop grandes. Une interface qui déclare trop de méthodes oblige le développeur à fournir beaucoup d’implémentations pour des méthodes qu’il n’est même pas sûr d’utiliser. Il en résulte que les interfaces sont souvent implémentés partiellement, l’implémentation des méthodes qui n’intéressent pas le développeur consistant à simplement lever une exception de type

NotImplementedException

 . Voilà qui est déjà une étrange manière d’aborder le problème, mais la descente dans le chelou ne va pas s’arrêter là.

Les classes abstraites

Il arrive qu’il y ait des cas d’utilisation où il faille forcer le développeur à réimplémenter des méthodes lui-même parce que le cas d’utilisation est beaucoup trop spécifique pour prendre le risque de fournir une implémentation généraliste. Cela arrive, entre autres, dans les bibliothèques d’algorithmes ; par exemple, dans les algos de tri de tableau. Le principe est de permettre au développeur de déclarer un objet comme étant comparable à un autre et permettant de le classer dans un tableau. Il n’est pas possible de fournir une implémentation par défaut d’une telle méthode car, par définition, l’algo de tri n’a aucune idée de la nature des objets qu’il va trier. Il n’a besoin que de savoir si tel objet comparé à tel autre se trouvera avant ou après lui dans l’ordre de classement. Cependant, s’il n’est pas possible de définir d’implémentation par défaut pour cette méthode en particulier. il peut y avoir une nécessité d’en fournir une pour d’autres méthodes de cette classe.

En particulier, j’ai rencontré ce cas d’utilisation lors de l’écriture d’une classe de gestion de liste de lecture pour un projet Android à l’école. Cette classe déclarait un grand nombre de méthodes utilitaires pour effectuer des requêtes en base de données. Ces méthodes n’étaient pas spécialement liées à la gestion de la liste de lecture mais utilisées lors de son instanciation. Le problème est que le grand nombre de ces méthodes utilitaires rendaient le code lourd et verbeux sans avoir de rapport direct avec le travail de la classe elle-même. Comme ce ne sont que des méthodes utilitaires, créer une classe à part entière était inutile puisque ça n’aurait été qu’un objet vide et une consommation inutile de mémoire. Les déclarer statique dans une classe à part entière avec un constructeur privé n’était pas non plus possible puisque ces méthodes agissaient quand-même sur des variables d’instance de l’objet qu’il aurait alors fallu passer en paramètre aux méthodes, ce que je trouve inélégant.

La solution générale à ce problème, c’est la classe abstraite.

Une classe abstraite est simplement une classe qui peut déclarer des méthodes avec des implémentations et des constructeurs, mais qui n’est juste pas instanciable. J’ai donc déclaré une classe abstraire contenant les implémentations des méthodes utilitaires ce qui me permet de les rendre disponibles sans effort et sans avoir à contourner les limitation d’un lien de composition.

Les classes abstraites sont aussi vieilles que le C++ et ont été reprises en Java. Java propose donc trois niveaux de déclaration d’objets : les classes, les classes abstraites et les interfaces qui sont des classes abstraites sans variables d’instance et sans méthodes implémentées.

Java 8 et les méthodes par défaut

La bibliothèque standard de Java repose énormément sur les interfaces. À tel point que c’en est ridicule. À un moment de mon apprentissage de Java, j’ai fini par me rendre compte qu’une grosse partie de mon temps passé à lire la documentation de Java consistait à retrouver une classe qui fournisse une implémentation d’une interface car les 3/4 des méthodes en Java demandent une interface en paramètre. Ouvrir un simple fichier ou produire une conversion de date dans un autre calendrier devient une véritable plaie.

Le plus drôle, c’est que les concepteurs de la bibliothèque standard de Java se sont rendus compte de leur connerie dans la bibliothèque AWT. La programmation évènementielle en Java est une torture pour cette raison très précise. La quantité de code à écrire pour implémenter un simple écouteur d’évènements est longue comme un jour sans pain. AWT fourni des interfaces comme 

MouseListener

  pour implémenter des réactions à un évènement quelconque mais dans la même bibliothèque, l’API fournit également des classes qui implémentent ces interfaces comme

MouseAdaptater

et qui ne sont que des méthodes vides, qui ne contiennent aucun code ; elles ne font strictement rien.

Pourquoi écrire une interface si c’est pour fournir tout de suite son implémentation ? Autant créer seulement la classe, non ?

Mais tout ça n’est rien en comparaison de la nouveauté que nous réservait Java 8 et que, à mon grand étonnement, tout le monde à considéré comme une grande avancée du langage Java : les méthodes par défaut. Le principe d’une méthode par défaut est de permettre à une interface de fournir une implémentation retenue par défaut si la classe ne déclare pas la sienne. Résumons : une interface est une classe qui ne peut-être instanciée et dont les méthodes ne déclarent pas d’implémentation… sauf si vous choisissez de déclarer une implémentation.

En Java 8, une interface est donc… une classe abstraite. Sans le dire, Java réintroduit donc dans son langage l’héritage multiple et donc, le problème du diamant.

La solution du C++

Le pire dans tout ça, c’est que Java a proposé, par le biais des interfaces, une solution à un problème qui avait déjà été résolu en C++. Dans ce langage, ce problème est appelé une ambiguité. Si le compilateur ne parvient pas à déterminer clairement quelle est l’implémentation qui prévaut, il lève une exception et oblige le développeur à fournir une implémentation explicite de la méthode. Cette solution est très élégante et aurait pu être facilement résolue en Java avec le mot-clef 

default

  introduit en Java 8. Il aurait alors suffit de déclarer quelque chose du type :

default uneMethode = ClasseMereA.uneMethode;

Même pas besoin de définir une implémentation spécifique, on précise juste que la bonne implémentation est celle de telle classe.

Python aussi permet l’héritage multiple. Cependant, pour déterminer l’implémentation qui prévaut, le langage utilise un algorithme qui permet de déterminer leur ordre de priorité et Scala, un langage compatible avec la machine virtuelle de Java fonctionne sur le même principe. Donc cette limitation est vraiment un choix technique assumé par les concepteurs du langage.

Et l’argument de la robustesse des applications qu’ils avancent ne tient vraiment pas la route car les programmes développés en C++ et en Python ne sont statistiquement pas plus bugués que les autres. Il suffit d’être bien concient de ce qu’on est en train de faire au moment où on le fait. Et, sur une note plus personnelle, j’ai toujours eu du mal à comprendre cet argument qui veut que ce soit le langage qui décide, pour la propre sécurité du développeur, ce qu’il peut écrire ou pas. Se priver de fonctionnalités qui pourraient résoudre des cas d’utilisation un peu exotiques de manière élégante juste parce que le développeur pourrait l’utiliser n’importe comment n’est pas un argument intelligent à mes yeux. Il est ridicule de subventionner des recherches en informatique théorique, de former des ingénieurs pendant des années et leur donner des cours d’algorithmique pour finir par ne les laisser développer qu’avec un langage à roulettes et les empêcher de tomber.

La solution de Groovy et Python

En SmallTalk, en Python, en Ruby et en Groovy, la solution à ce problème est encore plus élégante. Ces quatre langages ont suivis les principes originels de la POO énoncés par Kay en déterminant le type des objets non pas statiquement à la compilation, mais dynamiquement à l’exécution. Cette fixation tardive (late-binding) permet de ne pas s’attarder sur le type des objets eux-mêmes mais sur ce qu’ils sont capables de faire. On appelle ça le typage canard (duck typing). le principe est simple : si ça vole comme un canard, que ça gueule comme un canard et que ça nage comme un canard, alors c’est un canard.

Avec une telle manière de programmer, on en a rien à foutre des interfaces. Savoir si tel objet respecte tel contrat définit par telle interface et peut être traité comme tel n’a strictement aucun intérêt. La seule question qui a du sens est : « est-ce que mon objet possède la méthode que j’essaie d’appeler ? ». Si oui, alors le langage considère que le développeur a fait son boulot et là, c’est à lui de prendre ses responsabilités. Si non, il lève une exception pour dire au développeur qu’il a merdé quelque part.

C’est une solution simple et je n’ai d’ailleurs pas connaissance que les interfaces existent en tant que tel en Python ou en Ruby.

Il faut se rendre à l’évidence : Java est un mauvais langage, fondé de mauvais principes et avec de mauvaises idées qui ont mal tourné. Il existe, certes, des alternatives. J’en ai cité quelques-unes dans cet article mais, malheureusement, Java continue d’occuper la haut de la chaîne et d’être le langage dominant en entreprise, parce que personne, en école d’ingénieur, ne forme à d’autres langages…

Déjà 21 avis pertinents dans Les interfaces sont-elles un mauvais patron de conception ?

  • Cyril
    Hello !
    Ton article me fait pense à celui d’oncle Bob : http://blog.cleancoder.com/uncle-bob/2015/01/08/InterfaceConsideredHarmful.html
    De manière générale je ne suis pas très fan de l’héritage, auquel je préfère la composition. J’aime d’ailleurs assez
    go-lang pour son principe d’interfaces implémentées implicitement, qui donne un air de python à l’utilisation.
    Après le souci de la composition, c’est qu’on peut avoir à faire pas mal de transfert d’appel.. mais je vis avec ^^
  • djell
    En lisant votre article, j’ai l’impression de voir un vrai crachat sur le langage, pourtant il est argumenté et crédible. Rassurez moi vous n’êtes pas développeur Java? Cracher sur une partie de la conception de java, bien vous en fasse, mais venir ensuite utiliser le code du même langage comme exemple dans un autre article(celui que vous avez mis en lien) …. vous comprenez ce que je veux dire!!!Vous avez très certainement raison dans votre argumentaire, mais bon ça le fait pas trop je trouve.
  • djell
    En fait, vous détestez vraiment le langage Java, ? (vous avez le droit)
    Pourquoi ne pas vous mettre au C plus plus en autodidacte? Vous allez apprécier à mon avis (surcharge d’opérateurs, passage par adresses ou par références, PAS d’interfaces, PAS de garbage collector) Je suis étudiant en première année de BTS Systèmes Numériques, j’ai fait du java l’année dernière quand j’étais en DUT informatique (que j’ai raté). On va dire que je connais les bases de java et de la POO(notions de classes, d’objets, d’héritages, je commence à comprendre le polymorphisme…, liaison dynamique… que dalle). Je sais ce que c’est qu’une interface , je sais que ça sert à définir un type abstrait, mais j’admets que moi aussi, j’ai du mal à en comprendre l’utilité. Quand est ce qu’on s’en sert ? Quand préférer les classes abstraites?
    Pourquoi la plupart des gens disent que Java, c’est LE langage orienté l’objet? (Ca n’a pas l’air faux, même pour une simple saisie au clavier, il faut instancier la classe Scanner, les String sont des Objets, tous les types primitifs ont leur wrapper dans le SDK et il y a même ce mécanisme d’autoboxing qui permet de convertir un type primitif en un objet).
    Et puis moi ce ne me plait pas en java, c’est que le contact avec la machine, il est vraiment superficiel contrairement au C ou au C ++. On est obligé de passer par des méthodes natives qui font appel à du code écrit en C, qui LUI fera ce pourquoi il est appelé. (langage de haut niveau obligue).
    Et puis les interfaces graphiques en Java, MON DIEU QUELLE HORREUR. Je n’y ai JAMAIS RIEN compris. Mais est ce que ce n’est lié que à ce que vous expliquez dans l’article?
  • djell
     » je déteste qu’il y ai si peut d”opérateurs et qu’ils ne soient pas surchargeables »
    Je suis d’accord avec toi sur ce point là, c’est regrettable. (c’est l’effet c++)

    « je déteste que la manipulation des chaînes de caractères soient si ridiculement compliqué »
    C’est à dire? Ils l’ont trop simplifié à votre gout? Ou alors, à trop vouloir la simplifier, ils l’ont compliqué ?

    « qu’on puisse pas déclarer des listes ou des dictionnaires en compréhension »
    J’ai pas utilisé les collections proposées par le SDK,la seul e que je connaisse, c’est la liste contigue, que j’ai codé et il y a aussi la liste chainée, mais ça c’est le prof qui nous l’a codé, en démo. Et les dictionnaires en compréhension, je ne connais pas.

     » je déteste avoi à instancier des Builder de Maker de Factory pour pouvoir lire un con de fichier »
    En instanciant la classe Scanner, on peut le faire. Par contre, je ne me souviens plus quel constructeur le fait dans cette classe.

    « je déteste qu’il n’y ai pas de fonctions anonymes  » :
    Fonctions anonymes, je connais mais j’irais voir sur google.

    « Il y a même des fois où je trouve moyen de m’éclater à faire du Java. »
    Tant mieux pour toi :)

    « Je connais déjà C++ et j’aime pas plus sauf en duo avec la biblio Qt »

    Je commence à connaitre un petit peu le c++. Qt je connais pas mais je sais que ça sert à faire des interfaces graphiques avec des widgets… et pleins d’autres bonnes choses de ce style.

    « la bibliothèque standard est ridiculement petite. »
    Moi aussi je reprochais la même chose au C, mais c’est normal, quand à côté, on apprend un langage où le travail est maché (parfois de manière exagéré).

     » Le seul cas d’utilisation, c’est quand t’as pas le choix, c’est à dire quand l’API t’oblige à implémenter une interface. À l’extrême limite, quand t’as besoin de simuler un héritage multiple (mais c’est assez rare). Pour le reste, il n’y a strictement rien qu’une interface permet qu’une classe abstraite ou un lien de composition ne permette pas.  »
    Bah à la base, il me semble que c’était surtout pour « remédier » à l’absence de l’héritage multiple.

    « Oui mais c’est ça le problème : un vrai langage objet ne connaît pas de type primitifs. »
    Oui mais dans ce cas, si dans ton main, tu dois créer des variables de types primitifs (mettons des entiers), que tu dois les utiliser pour l’appel d’un constructeur, comment tu fais sans type primitifs ? Et puis quand tu code une classe objet (avec les attributs et les méthodes), pour pouvoir décrire l’objet, créer un nouveau type, il faut bien partir de quelque chose, non? Et en programmation procédurale, on fait comment? (Tu te dis développeur, donc ma question va surement te paraitre idiote, mais c’est là qu’on voit que je débute et comme je l’ai dit, jsuis loin d’être un as de la prog, je n’ais qu’un ans de DUT).

  • djell
    Sur le Groovy, je ne m’avancerais pas trop car je ne connais pas le langage. Mais effectivement ça parait façile vu sous cette angle.

    « Si tu tapes myInt = 1, c’est un objet, et, en fait, ce que tu as tapé, c’est : myInt = int(1). Tout est toujours un objet. »
    Ca voudrait en fait que si je suis ma logique qui est très scolaire pour l’instant, il y a déjà un constructeur pour même pour une donnée de base comme un entier?

    « C’est pas facile d’expliquer tout ça pour moi parce que, déjà je connais pas ton niveau en dev donc je sais pas trop quelq concepts ont à ta porté et lesquels je dois plus développer, mais surtout parce que c’est des connaissances que j’ai moi-mêmes acquises avec de nombreuses lectures et en essayant plusieurs langages. »

    Oui je comprend, mais là en fait si je te suis, il faudrait remettre en cause tout une partie de mes connaissances en programmation.
    Rien que l’histoire du type primitif qui ne devrait pas exister (sinon pourquoi l’autoboxing en Java?) qui est un objet et qui n’existe qu’une fois le code traduit en assembleur, déjà c’est « énorme ».

    Pareil pour les fonctions, cad que pour moi une fonction ou une méthode, c’est un bout de code avec un identificateur et des paramètres éventuels, qui fait un traitement et qui renvoie éventuellement des résultats, ça rend un programme plus facile à maintenir car quand il y a une erreur, on ne la corrige qu’une seule fois… (je te refais pas le refrein, tu le connais déjà). J’aurais jamais imaginé ça comme un objet surtout avec ma vision purement scolaire de la POO(entièrement fausse?). Car comment je décris un bout de code dans une classe, qui est la seule référence que je connais en objet, sachant qu’il y a d’autres choses que les classes? Comment je respecte le principe d’encapsulation? Comment je fais pour définir ma fonction comme l’instance d’une classe?Tu vois ce que je veux dire? Et peut être qu’ en Python, on n’utilise pas les classes, je n’en sais rien, je ne connais pas Python dans les détails. Et tu vois, ce qui pour moi est le pire, c’est que j’ai appris les bases de la programmation avec Java, mais le refrein sera le même pour tous les autres langages de la famille C(c++ , C# …). Et c’est la même pour les type primitifs. Ma vision se limite à celle qu’on nous apprend à l’IUT ou en BTS, c’est à dire, le type primitif et les autres et effectivement cette limitation de la réflexion au niveau du fonctionnement en mémoire.

  • djell
    Tiens maintenant que j’y pense, ton article porte sur les interfaces en Java qui représente, selon toi un vrai handicap. A un moment donné, tu parlais du C#, je ne sais plus à quel occasion (je crois que c’était pour les interfaces graphiques). Tu pense quoi toi de ce langage qui reprend le principe des interfaces de java ?
    Si je te pose la question c’est que j’ai regardé un peu les tutos sur ce langage et j’ai été assez stupéfait des ressemblances syntaxiques et de conception des deux langages. C’est vrai, regardes, en C# tu n’as pas d’héritage multiple, pour écrire le moindre petit algo, tu dois créer une classe. Je crois aussi (mais à vérifier) qu’il existe une super classe NSObject (Dailleur crois tu que l’idée de la super classe, du genre Object soit une connerie? ). C# reprend le concept d’interface qui selon toi est inutile mais avec des différences que je ne connais pas. Il me semble aussi que l’on peut surcharger les opérateurs en C# mais c’est encore à vérifier.
    Pense tu que les concepteurs du C# ont fait la même connerie que ceux de Java?
  • djell
    Il y avait un autre truc aussi, le compilateur est en Français (en 2 ans de prog, c’est une première) mais bon c’est un détails auquel j’accorde une importance relative.
    Bon, en tout cas merci hein, c’est toujours bien d’avoir l’avis d’un vrai développeur, même si je trouve que ça le fait pas trop de mettre en avant les faiblesse de Java puis de réutiliser son code ailleurs (je respecte quand même votre opinion). Celà dit même si j’aime bien coder en Java, je ne le trouve pas parfais, loin de là. :)
  • Lucas
    Je ne pense pas que les interfaces soient un mauvais patron de conception, je dirais même que c’est l’héritage qui en est un. Il est en effet préférable d’utiliser la composition plutôt que l’héritage, je te renvoie vers une bonne vidéo qui parle de ça https://www.youtube.com/watch?v=wfMtDGfHWpA

    Les interfaces permettent de décrire le comportement d’un objet en se fichant de son implémentation. Cela ouvre la porte au polymorphisme, à l’injection de dépendances, etc. Imaginons par exemple une interface UserReposiory qui définit une méthode findOneByEmail(). on pourrait ainsi avoir une implémentation MysqlUserRepository, InMemoryUserRepository, etc. Ainsi, par exemple lorsque tu fais tes tests tu peux directement mocker l’interface et quand tu auras besoin de récupérer un User tu demanderas un objet du type UserRepository tout simplement.

  • Lucas
    Je ne suis pas trop au courant de ce qui se passe dans le monde Java mais le principe des interfaces est très similaire dans d’autres langages.

    De mon point de vue, l’interface ne propose aucune fonctionnalité que ne propose pas déjà la classe abstraite.

    Tu ne peux étendre que d’une seule classe abstraite mais tu peux implémenter plusieurs interfaces. Avec la classe abstraite tu hérites d’une classe de base que tu étends, avec une interface tu acquiers une capacité à faire certaines choses. Certains suffixent leurs noms d’interface par « able »: être apte à.

    C’est aussi pour cela que généralement les classes abstraites deviennent des fourre tout immondes alors que les interfaces te permettent d’avoir un code réutilisable, modulaire et testable.

    En en discutant avec un collègue, il me disait que ce qu’il trouvait bien à l’interface, c’est qu’elle te garantissait qu’aucun effet de bord serait généré par l’implémentation.

    Oui, c’est aussi le principe du typage fort, on type les arguments des méthodes et si un mauvais type est passé, ça pète. Quand tu types avec une interface, tu passes un contrat avec ta dépendance, ça permet une meilleure lisibilité du code, une meilleure testabilité, une meilleure cohérence. Mais comme toujours, cela demande plus de rigueur et de lignes de codes. Ca a l’air de servir à rien pour un petit projet qui peut se faire dans un fichier en 30 lignes de script mais ça sert beaucoup quand tu bosses sur un gros projet et que tu deal avec de la complexité et beaucoup de logique métier. Y’a qu’à voir les principes SOLID https://en.wikipedia.org/wiki/SOLID_(object-oriented_design) que tout bon développeur expérimenté se doit d’essayer de respecter, pour se rendre compte que les interfaces sont très utiles (voir le Interface segregation principle).

    Sauf que ça pose au moins un gros problème pour moi : ça pète l’encapsulation puisque tu es obligé de te demander si tu hérites d’une interface ou non.

    Je t’avoue que je ne comprends pas ce que tu veux dire car pour moi l’encapsulation d’un objet est sa capacité à ne fournir qu’une seule manière de modifier son état (à travers des méthodes), l’implementation d’interface rend la chose plus claire car en regardant les interfaces qu’il implémente tu sais ce qu’est capable de faire ton objet. Dans tous les cas l’implémentation d’interface n’est pas obligatoire pour les classes et ne doit pas être systématique, cela répond just à un certain besoin, comme tout. Tu peux très bien composer tes objets avec l’injection de dépendances sans forcément utiliser d’interface. Une interface signifie juste que tu peux avoir différentes implémentations de celle ci.

    Et la composition aussi me pose un très gros problème puisque c’est un pattern qui pète une des règles fondamentales du développement de logiciels : DON’T FUCKING REPEAT YOURSELF. Sauf que quand tu composes, tu dois écrire toutes les méthodes déléguées. C’est du temps perdu.

    Tu peux toujours te servir des mixins et des traits (je dis ça sans vouloir me focaliser sur un langage en particulier).

    PS : le type de la vidéo que tu cites commence par un principe malheureusement assez bête : les interfaces décrivent ce qu’un objet peut faire quand l’héritage détermine ce qu’il est. Sauf que c’est la même chose.

    Non, il ne parle pas d’interface, il parle de composition vs héritage, tu peux très bien composer sans interface, c’est ce qu’il fait d’ailleurs. Normalement si tu as regardé la vidéo, t’aurais dû comprendre que justement « what you are » et « what you do » c’est pas la même chose… il le prouve assez bien pourtant.

  • Lucas
    Je te parle de la philosophie et des concepts de la POO et tu me parles de Java et de technique, je pense pas qu’on ne regarde la chose sous le même angle.

    Dire qu’il n’y a rien que tu puisses faire avec une interface que tu ne puisses pas avec une classe abstraite c’est comme dire qu’il n’y a rien que tu puisses faire en procédurale que tu ne puisses faire en objet. Il y’a des milliards de possibilités pour arriver au même rendu, seulement y’a des gens qui ont inventé des best practices(S.O.L.I.D., Object calisthenics…), des designs patterns (IoC…) et des méthodes de développement (DDD, TDD, BDD…), libre à toi de les respecter ou non.

    Donc oui, tu peux mocker une classe abstraite, même des méthodes privées à ce qu’il parait mais c’est pas ce que je ferai personnellement.

Les commentaires sont fermés.