Est-ce une mauvaise habitude de ne pas utiliser d'interfaces? [fermé]

40

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?
Jineesh Joseph
la source
10
Quelle langue est-ce?
2
En plus de quelle langue, de quel paradigme s'agit-il?
Armando
1
Le concept d '"interface" ne transcende-t-il pas le langage? Java a le type d'interface intégré, mais les développeurs C ++ créent souvent aussi des interfaces (en les préfixant avec I) et elles servent toutes le même but.
Ricket
4
@Ricket: Non, pas vraiment. Le problème est que C ++ offre l'héritage de plusieurs classes. En C ++, une "interface" est beaucoup plus conceptuelle et en réalité, nous utilisons principalement ce qu'ils définiraient comme une classe de base abstraite. #
DeadMG
2
@Ricket Non, surtout si vous travaillez dans un langage fonctionnel plutôt que dans un langage procédural ou POO.
alternative

Réponses:

36

Vous pouvez utiliser des interfaces pour plusieurs raisons:

  1. Les interfaces conviennent aux situations dans lesquelles vos applications nécessitent de nombreux types d'objet éventuellement non liés pour fournir certaines fonctionnalités.
  2. Les interfaces sont plus souples que les classes de base car vous pouvez définir une seule implémentation pouvant implémenter plusieurs interfaces.
  3. Les interfaces sont meilleures dans les situations dans lesquelles vous n'avez pas besoin d'hériter de la mise en œuvre d'une classe de base.
  4. Les interfaces sont utiles dans les cas où vous ne pouvez pas utiliser l'héritage de classe. Par exemple, les structures ne peuvent pas hériter des classes, mais elles peuvent implémenter des interfaces.

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".

Robert Harvey
la source
13
Son langage n'est pas spécifié et le vôtre est trop spécifique. Par exemple, en C ++, une structure peut en effet hériter d'une classe et vous pouvez multiplier l'héritage de bases non abstraites.
DeadMG
2
Cette réponse semble être en C # mais concerne également Java si vous supprimez le n ° 4, et ne s'applique en quelque sorte qu'au C ++ car, bien entendu, l'héritage multiple est autorisé en C ++.
Ricket
2
De plus, je ne suis pas d'accord avec la dernière déclaration. Je pense qu'il y a beaucoup de bonnes pratiques que les programmeurs devraient faire mais ne le font pas car ils estiment ne pas en avoir besoin. Je pense que le demandeur est très sage en regardant autour de lui, en voyant tout le monde faire cette chose et en pensant qu'il devrait peut-être le faire aussi, mais en demandant "pourquoi" en premier.
Ricket
3
@Ricket: Le pourquoi est dans les quatre points de ma réponse. Si aucune de ces raisons ne s’applique, vous n’avez pas besoin d’une interface.
Robert Harvey
17

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. "

John Connelly
la source
2
Eh bien, je l'ai lu et j'ai pensé que c'était une bonne réponse.
Eric King
1
@ mc10 Vous ne savez pas quel est le problème. Il a fait référence à un livre et la moitié inférieure de sa réponse est simplement des citations de ce livre qu'il vous indique clairement au cas où vous ne voudriez pas perdre votre temps.
Pete
@Pete Je n'ai pas dit que la réponse était mauvaise, mais seulement que c'était un peu trop long. Je doute que vous ayez eu besoin de la citation complète parfois.
kevinji
3
haha, si c’est bien, je ne suis pas sûr que vous aimiez cette histoire de réponses StackExchange.
Nic
haha, merci les gars. Oui, il m'est apparu que la réponse était un peu longue, mais je pensais pouvoir nuancer ma réponse en incluant des citations pertinentes de M. Wagner qui exposaient les avantages et les inconvénients des interfaces par rapport à l'héritage, ainsi que les scénarios dans lesquels: chacun est plus approprié. Citer le livre directement n’a peut-être pas ajouté beaucoup de valeur à ma réponse.
John Connelly
8

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 utilisiez IList<T>tout votre code, le changer pour l'utiliser AwesomeList<T>signifierait changer seulement quelques dizaines de lignes, plutôt que quelques centaines / milliers.

BlueRaja - Danny Pflughoeft
la source
5

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.

Karl Bielefeldt
la source
4

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.

DeadMG
la source
1
Raison de downvote?
DeadMG
Pas sûr, avoir un upvote. C'était une bonne réponse.
Bryan Boettcher
3

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.

Michael Borgwardt
la source
3

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).

JUSTE MON AVIS correct
la source
2

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.

Donal Fellows
la source
1

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
0

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:

class B; // forward declaration
class A
{
  B* b;
};

class B
{
  A* a;
}

Pas mal:

class PartOfClassB_AccessedByA
{
};

class A
{
  PartOfClassB_AccessedByA* b;
};

class B : public PartOfClassB_AccessedByA
{
  A* a;
}

Généralement, A, B, PartOfClassB_AccessedByA sont implémentés avec des fichiers séparés.

9dan
la source
0

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].

Amit Patel
la source