Dans l'entreprise où je travaille, chaque classe de service a une interface correspondante.
Est-ce nécessaire?
Remarques:
Avec des bibliothèques de moqueries modernes capables de se moquer de classes concrètes et des IDE capables d'extraire une interface d'une classe en deux clics environ, est-ce juste un maintien des temps antérieurs?
Votre entreprise suit les principes SOLID et le ciblage d'une interface plutôt que d'une classe concrète n'ajoute aucun frais supplémentaire au programme. Ce qu'ils font est une quantité très modérée de travail supplémentaire qui peut rapporter des volumes lorsque les hypothèses que vous faites finissent par être fausses ... et vous ne pouvez jamais dire quelle hypothèse cela va être. Ce que vous recommandez tout en travaillant un peu moins, peut coûter beaucoup, beaucoup, beaucoup d'heures de refactoring qui auraient pu être juste fait à l'avance en suivant simplement les principes de base de la conception OO.
Vous devriez apprendre de ces gars et vous considérer comme chanceux. J'aimerais avoir travaillé dans un tel environnement où un design solide était un objectif prioritaire.
Compte tenu de votre question, je suppose que les raisons de ce type de conception ne sont pas documentées.
L'utilisation injustifiée d'une interface avec une seule implémentation est tout à fait erronée car cela viole YAGNI . D'après mon expérience, cela a également été assez dommageable pour la maintenance, principalement parce que les méthodes implémentant l'interface sont forcées d'être inutilement publiques. Après avoir accumulé plus d'expérience refactoring , vous apprendrez probablement à apprécier le charme modeste de privé et package privé modificateurs d'accès permettant un pour concentrer l'attention au sein d'une seule classe/package.
Quant à l'utilisation non documentée justifiée de cet idiome, c'est à mes yeux à peu près aussi mauvaise - tout d'abord parce qu'elle ne permet pas à un responsable de "dire bon de mauvais ". Par conséquent, cela laisse entre des options pas très attrayantes. Les options sont, soit vous gardez les trucs publics douteux tels quels, donc à plusieurs reprises diminuant la productivité chaque fois que vous devez changer le code, ou vous apportez des changements risqués en "effondrant" aveuglément l'implémentation unique en une maintenance plus facile POJO - s'exposant au risque de découvrir douloureusement que c'est la mauvaise façon, que certains autres ( Dieu ne plaise, à distance ) module hors de votre vue attend l'interface.
J'ai vécu plusieurs fois des "révélations" causées par l'effondrement erroné d'une interface à implémentation unique. Chaque fois, ça a été une expérience assez éducative mais je ne voudrais pas vraiment y retourner. Le fait est que cela se produit à des tests tardifs, à l'intégration ou même à l'acceptation des utilisateurs et que l'annulation/la correction de l'erreur commise il y a longtemps à ce stade est assez lourde.
Je ne pouvais tout simplement pas voir le côté pratique ... les interfaces sont utilisées de manière individuelle comme
com.company.service.foo
etcom.company.service.foo.impl
Vous trouverez ci-dessous comment je gère généralement des cas comme celui-ci.
PRJ-123
Utilisation douteuse non documentée de l'interface avec une seule implémentation dans Foo/FooImpl ".Attendez un peu au cas où quelqu'un viendrait expliquer les choses. J'attendrais au moins une semaine ou deux
Foo
javadocs quelque chose comme le but de l'interface expliqué dans le ticket PRJ-123, c) fermez le ticket, d) sauter les trois étapes suivantes.PRJ-123
): documenter le but ou réduire à POJO.Voici comment Adam Bien pensez à cette question: Service s = new ServiceImpl () - Pourquoi faites-vous cela?
Ce n'est pas seulement un ballonnement (et l'opposé de l'idée de "Convention sur la configuration"), mais cela cause de réels dégâts:
- Imaginez que vous obteniez une autre implémentation (c'est tout l'intérêt d'une interface) - comment la nommeriez-vous?
- Il double la quantité d'artefacts - et augmente considérablement la "complexité"
- C'est vraiment drôle de lire les javadocs sur l'interface et l'impl - une autre redondance
- La navigation dans le IDE est moins fluide
et je suis d'accord avec lui.
Peut-être que vos collègues sont toujours coincés dans le temps avec J2EE, car cela était nécessaire lorsque vous travaillez avec J2EE, vous pouvez peut-être trouver sur Internet d'anciens tutoriels sur les moments difficiles dans J2EE.
Les interfaces Java ne concernent pas seulement la possibilité de se moquer (bien sûr, c'est un facteur). Une interface expose un contrat public pour votre service, sans détails d'implémentation tels que des méthodes ou des attributs privés.
Notez que "public" lors de l'utilisation de services internes (comme dans votre cas) fait référence aux utilisateurs réels desdits services, y compris - mais sans s'y limiter - d'autres programmeurs et services internes!
Une raison possible pour chaque classe de service d'avoir une interface est qu'elle rend les interactions avec des frameworks sophistiqués (par exemple, Spring, JEE) beaucoup plus simples. En effet, Java peut simplement générer des objets intercepteurs sur des interfaces (voir Java.lang.reflect.Proxy
); le faire contre des classes concrètes est beaucoup plus délicat et rempli de mises en garde non évidentes lorsque vous travaillez avec plusieurs chargeurs de classe différents. Cela est d'autant plus vrai si vous travaillez avec OSGi, où ces interfaces de service finiront par être chargées à partir d'un chargeur de classe différent des implémentations de ces services. Cela (avec le tissu de découverte de services), à son tour, impose une séparation très forte entre chaque service et ses clients; les clients littéralement ne peuvent pas briser l'abstraction.
Sachez que même si un IDE peut extraire une interface d'une classe en un seul clic, cela ne signifie pas nécessairement qu'il va extraire l'interface correcte. L'intelligence est toujours nécessaire.
Il semble comme une surcharge d'utiliser initialement l'Interface .. mais plus tard, lorsque nous devons étendre certaines fonctionnalités, ces Interfaces aident beaucoup.
Si vous ne faites qu'une implémentation concrète, vous devez beaucoup changer l'implémentation du code. Mais en utilisant l'interface, vous avez juste besoin d'ajouter une nouvelle classe qui implémente le contrat d'Interface (et vous pouvez appeler un nouvel objet de classe à partir de la variable de référence de l'ancienne interface) .