J'utilise rarement les interfaces et je les trouve communes dans d'autres codes.
De plus, je crée rarement des sous-classes et des super classes (tout en créant mes propres classes) dans mon code.
- Est-ce une mauvaise chose?
- Souhaitez-vous suggérer de changer ce style?
- Est-ce que ce style a des effets secondaires?
- Est-ce parce que je n'ai pas travaillé sur de grands projets?
programming-practices
coding-style
interfaces
Jineesh Joseph
la source
la source
Réponses:
Vous pouvez utiliser des interfaces pour plusieurs raisons:
http://msdn.microsoft.com/en-us/library/3b5b8ezk(v=vs.80).aspx
Les interfaces sont comme n'importe quoi d'autre dans la programmation. Si vous n'en avez pas besoin, ne les utilisez pas. Je les ai vus fréquemment utilisés pour des raisons de style, mais si vous n'avez pas besoin des propriétés et des fonctionnalités spéciales fournies par une interface, je ne vois pas l'avantage de les utiliser "juste parce que".
la source
L'héritage de classe et les interfaces ont tous deux leur place. Héritage signifie "est un" alors qu'une interface fournit un contrat qui définit ce à quoi "se comporte".
Je dirais que l'utilisation d'interfaces plus souvent n'est pas une mauvaise pratique du tout. Je suis en train de lire "Effective C # - 50 moyens spécifiques d'améliorer votre C #" de Bill Wagner. Le numéro d'article 22 indique, et je cite, "Préférer la définition et la mise en oeuvre d'interfaces à l'héritage".
En général, j'utilise des classes de base lorsque je dois définir une implémentation spécifique du comportement commun entre types apparentés. Plus souvent, j'utilise des interfaces. En fait, je commence normalement par définir une interface pour une classe lorsque je commence à en créer une ... même si au final je ne compile pas l'interface, je trouve qu'il est utile de commencer par définir l'API publique de la classe. classe dès le départ. Si je constate que plusieurs classes implémentent l'interface et que la logique d'implémentation est identique, ce n'est qu'alors que je me demanderai s'il serait judicieux d'implémenter une classe de base commune entre les types.
Quelques citations du livre de Bill Wagners ...
toutes les classes dérivées incorporent immédiatement ce comportement. L'ajout d'un membre à une interface annule toutes les classes qui implémentent cette interface. Ils ne contiendront pas la nouvelle méthode et ne compileront plus. Chaque implémenteur doit mettre à jour ce type pour inclure le nouveau membre. Choisir entre une classe de base abstraite et une interface dépend de la meilleure façon de prendre en charge vos abstractions au fil du temps. Les interfaces sont corrigées: vous publiez une interface sous forme de contrat pour un ensemble de fonctionnalités que tout type peut implémenter. Les classes de base peuvent être étendues avec le temps. Ces extensions font partie de chaque classe dérivée. Les deux modèles peuvent être combinés pour réutiliser le code d'implémentation tout en prenant en charge plusieurs interfaces. " Ils ne contiendront pas la nouvelle méthode et ne compileront plus. Chaque implémenteur doit mettre à jour ce type pour inclure le nouveau membre. Choisir entre une classe de base abstraite et une interface dépend de la meilleure façon de prendre en charge vos abstractions au fil du temps. Les interfaces sont corrigées: vous publiez une interface sous forme de contrat pour un ensemble de fonctionnalités que tout type peut implémenter. Les classes de base peuvent être étendues avec le temps. Ces extensions font partie de chaque classe dérivée. Les deux modèles peuvent être combinés pour réutiliser le code d'implémentation tout en prenant en charge plusieurs interfaces. " Ils ne contiendront pas la nouvelle méthode et ne compileront plus. Chaque implémenteur doit mettre à jour ce type pour inclure le nouveau membre. Choisir entre une classe de base abstraite et une interface dépend de la meilleure façon de prendre en charge vos abstractions au fil du temps. Les interfaces sont corrigées: vous publiez une interface sous forme de contrat pour un ensemble de fonctionnalités que tout type peut implémenter. Les classes de base peuvent être étendues avec le temps. Ces extensions font partie de chaque classe dérivée. Les deux modèles peuvent être combinés pour réutiliser le code d'implémentation tout en prenant en charge plusieurs interfaces. " Vous publiez une interface sous forme de contrat pour un ensemble de fonctionnalités que tout type peut implémenter. Les classes de base peuvent être étendues avec le temps. Ces extensions font partie de chaque classe dérivée. Les deux modèles peuvent être combinés pour réutiliser le code d'implémentation tout en prenant en charge plusieurs interfaces. " Vous publiez une interface sous forme de contrat pour un ensemble de fonctionnalités que tout type peut implémenter. Les classes de base peuvent être étendues avec le temps. Ces extensions font partie de chaque classe dérivée. Les deux modèles peuvent être combinés pour réutiliser le code d'implémentation tout en prenant en charge plusieurs interfaces. "
"Les interfaces de codage offrent une plus grande flexibilité aux autres développeurs que le codage des types de classes de base."
"L'utilisation d'interfaces pour définir des API pour une classe offre une plus grande flexibilité."
"Lorsque votre type expose des propriétés en tant que types de classe, l'interface entière est exposée à cette classe. À l'aide d'interfaces, vous pouvez choisir d'exposer uniquement les méthodes et les propriétés que les clients doivent utiliser."
"Les classes de base décrivent et implémentent des comportements communs entre types concrets associés. Les interfaces décrivent des fonctionnalités atomiques que des types concrets non liés peuvent implémenter. Les deux ont leur place. Les classes définissent les types que vous créez. Les interfaces décrivent le comportement de ces types en tant que fonctionnalités. Si vous comprenez les différences, vous créerez des conceptions plus expressives et plus résilientes face au changement. Utilisez des hiérarchies de classes pour définir les types associés. Exposez la fonctionnalité à l'aide d'interfaces implémentées entre ces types. "
la source
Une chose qui n’a pas été mentionnée est le test: dans toutes les bibliothèques de mocking C #, ainsi que dans certaines bibliothèques pour Java, les classes ne peuvent être simulées que si elles implémentent une interface. Cela conduit de nombreux projets suivant les pratiques Agile / TDD à donner à chaque classe sa propre interface.
Certaines personnes considèrent cette meilleure pratique, car elle "réduit le couplage", mais je ne suis pas d'accord - je pense que c'est simplement une solution de contournement à une déficience de la langue.
Je pense que les interfaces sont mieux utilisées lorsque vous avez deux classes ou plus qui, abstraitement, font la même chose, mais de manière différente.
Par exemple, le framework .Net a plusieurs classes qui stockent des listes de choses , mais toutes les stockent de différentes manières. Il est donc logique d’avoir une
IList<T>
interface abstraite , qui peut être mise en œuvre en utilisant différentes méthodes.Vous devez également l'utiliser lorsque vous souhaitez que deux classes ou plus soient interchangeables ou remplaçables à l'avenir. Si une nouvelle façon de stocker des listes apparaît dans le futur,
AwesomeList<T>
alors, si vous utilisiezIList<T>
tout votre code, le changer pour l'utiliserAwesomeList<T>
signifierait changer seulement quelques dizaines de lignes, plutôt que quelques centaines / milliers.la source
Le principal résultat de la non-utilisation de l'héritage et des interfaces lorsqu'elles sont appropriées est un couplage étroit . Cela peut être un peu difficile à apprendre à reconnaître, mais le symptôme le plus évident est que lorsque vous effectuez un changement, vous vous retrouvez souvent obligé de consulter d’autres fichiers pour effectuer des modifications dans un effet d’entraînement.
la source
Non, ce n'est pas mal du tout. Les interfaces explicites doivent être utilisées, si et seulement si, deux classes avec une interface commune doivent être interchangeables au moment de l'exécution. S'ils n'ont pas besoin d'être interchangeables, ne les faites pas hériter. C'est aussi simple que ça. L'héritage est fragile et doit être évité autant que possible. Si vous pouvez l'éviter ou utiliser des génériques à la place, faites-le.
Le problème est que, dans des langages comme C # et Java avec des génériques au moment de la compilation, vous pouvez violer DRY car il n’est pas possible d’écrire une méthode qui puisse traiter plus d’une classe à moins que toutes les classes héritent de la même base. C # 4
dynamic
peut faire face à cela, cependant.En réalité, l'héritage est comme des variables globales: une fois que vous l'ajoutez et que votre code en dépend, Dieu vous aide à le supprimer. Cependant, vous pouvez l'ajouter à tout moment, et vous pouvez même l'ajouter sans modifier la classe de base en utilisant un wrapper de sortes.
la source
Oui, ne pas (ou trop rarement) utiliser des interfaces est probablement une mauvaise chose. Les interfaces (au sens abstrait, et la construction du langage C # / Java est une assez bonne approximation de ce sens abstrait) définissent des points d'interaction explicites entre les systèmes et les sous-systèmes. Cela aide à réduire le couplage et rend le système plus facile à gérer. Comme pour tout ce qui améliore la facilité de maintenance, plus un système est gros, plus il est important.
la source
Je n'ai pas utilisé d'interface depuis des années. Bien sûr, c'est parce que je programme presque exclusivement à Erlang depuis des années et que le concept d'interface n'existe tout simplement pas. (Le plus proche que vous obtenez est un "comportement" et ce n'est pas vraiment la même chose sauf si vous plissez les yeux et que vous les regardez du coin de l'œil.)
Donc, vraiment, votre question dépend du paradigme (OOP dans ce cas) et, de plus, dépend vraiment beaucoup de la langue (il existe des langues OOP sans interfaces).
la source
Si vous parlez de l’utilisation de Java, l’une des raisons de l’utilisation des interfaces est qu’elles permettent l’utilisation d’objets proxy sans bibliothèques de génération de code. Cela peut être un avantage substantiel lorsque vous travaillez avec un cadre complexe comme Spring. De plus, certaines fonctionnalités requièrent des interfaces: RMI en est l'exemple classique, car vous devez décrire la fonctionnalité que vous fournissez en termes d'interfaces (héritées de
java.rmi.Remote
), quelle que soit la façon dont vous les implémentez.la source
Les choses changent ( MS Moles ), mais la principale raison pour laquelle je pense qu'il est bon de coder presque exclusivement en interfaces est qu’elles sont faciles à simuler et s’intègrent naturellement dans une architecture IoC.
Messagerie Internet, vous ne devez jamais utiliser que des interfaces ou des DAO complètement stupides dans la mesure du possible. Une fois que vous êtes entré dans cet état d'esprit et que vous commencez à utiliser une bibliothèque qui ne s'expose pas à travers les interfaces et qui fait tout via des objets concrets, je dois être honnête, tout se sent un peu maladroit.
la source
Pour les projets à l’ancienne, on utilise des interfaces pour éviter les références circulaires, car les références circulaires pourraient devenir un énorme problème de maintenance à long terme.
Mauvais:
Pas mal:
Généralement, A, B, PartOfClassB_AccessedByA sont implémentés avec des fichiers séparés.
la source
La programmation par interface permet de rendre le code plus flexible et plus facile à tester. Les classes d'implémentation peuvent être modifiées sans toucher au code client [Flexibility]. Tout en testant du code, on peut remplacer la programmation actuelle basée sur oInterface, ce qui rend le code plus flexible et plus facile à tester. Les classes d'implémentation peuvent être modifiées sans toucher au code client [Flexibility]. Lors du test du code, vous pouvez remplacer un objet réel par des objets fantômes [Testability] .bject par des objets fantômes [Testability].
la source