Question Interface vs classe de base


Quand dois-je utiliser une interface et quand dois-je utiliser une classe de base?

Devrait-il toujours être une interface si je ne veux pas réellement définir une implémentation de base des méthodes?

Si j'ai un cours de chien et chat. Pourquoi voudrais-je implémenter IPet au lieu de PetBase? Je peux comprendre avoir des interfaces pour ISheds ou IBarks (IMakesNoise?), Parce que ceux-ci peuvent être placés sur un animal de compagnie par animal de compagnie, mais je ne comprends pas lequel utiliser pour un animal de compagnie générique.


708


origine


Réponses:


Prenons votre exemple d'une classe Chien et Cat, et illustrons en utilisant C #:

Le chien et le chat sont tous deux des animaux, en particulier des mammifères quadrupèdes (les animaux sont trop généraux). Supposons que vous ayez une classe Mammale abstraite, pour les deux:

public abstract class Mammal

Cette classe de base aura probablement des méthodes par défaut telles que:

  • Alimentation
  • Camarade

Tous sont des comportements qui ont plus ou moins la même mise en œuvre entre les deux espèces. Pour définir ceci, vous aurez:

public class Dog : Mammal
public class Cat : Mammal

Supposons maintenant qu'il y a d'autres mammifères, que nous verrons habituellement dans un zoo:

public class Giraffe : Mammal
public class Rhinoceros : Mammal
public class Hippopotamus : Mammal

Ce sera toujours valable car au cœur de la fonctionnalité Feed() et Mate() sera toujours le même.

Cependant, les girafes, les rhinocéros et les hippopotames ne sont pas exactement des animaux dont vous pouvez faire des animaux de compagnie. C'est là qu'une interface sera utile:

public interface IPettable
{
    IList<Trick> Tricks{get; set;}
    void Bathe();
    void Train(Trick t);
}

La mise en œuvre pour le contrat ci-dessus ne sera pas la même entre un chat et un chien; mettre leurs implémentations dans une classe abstraite à hériter sera une mauvaise idée.

Vos définitions de chien et de chat devraient maintenant ressembler à:

public class Dog : Mammal, IPettable
public class Cat : Mammal, IPettable

Théoriquement, vous pouvez les remplacer à partir d'une classe de base supérieure, mais essentiellement une interface vous permet d'ajouter uniquement les choses dont vous avez besoin dans une classe sans avoir besoin d'héritage.

Par conséquent, parce que vous ne pouvez généralement hériter que d'une classe abstraite (dans la plupart des langages OO typés statiquement qui sont ... les exceptions incluent C ++) mais être capable d'implémenter plusieurs interfaces, cela vous permet de construire des objets strictement comme demandé base.


459



Eh bien, Josh Bloch s'est dit dans Java efficace 2d:

Préférer les interfaces sur les classes abstraites

Quelques points principaux:

  • Les classes existantes peuvent facilement être modernisées pour implémenter un nouveau   interface. Tout ce que vous avez à faire est d'ajouter   les méthodes requises si elles ne le sont pas encore   existe et ajoute une clause implements à   la déclaration de classe.

  • Les interfaces sont idéales pour définir les mixins. Autrement dit, un   mixin est un type qu'une classe peut   mettre en œuvre en plus de son "primaire   tapez "pour déclarer qu'il fournit   un comportement optionnel. Par exemple,   Comparable est une interface mixin   permet à une classe de déclarer que son   les instances sont ordonnées à l'égard de   d'autres objets mutuellement comparables.

  • Les interfaces permettent la construction de type non hiérarchique   cadres. Les hiérarchies de types sont   super pour organiser certaines choses, mais   d'autres choses ne tombent pas nettement dans un   hiérarchie rigide.

  • Les interfaces permettent des améliorations de fonctionnalités sécurisées et puissantes via le   wrap- par idiome de classe. Si tu utilises   classes abstraites pour définir les types, vous   quitter le programmeur qui veut ajouter   fonctionnalité sans alternative, mais   utiliser l'héritage.

De plus, vous pouvez combiner les vertus   des interfaces et des classes abstraites par   fournir un squelette abstrait   classe de mise en œuvre pour aller avec chaque   interface non triviale que vous exportez.

D'un autre côté, les interfaces sont très difficiles à faire évoluer. Si vous ajoutez une méthode à une interface, toutes ses implémentations seront interrompues.

PS .: Achetez le livre. C'est beaucoup plus détaillé.


134



Le style moderne est de définir IPet et PetBase.

L'avantage de l'interface est que l'autre code peut l'utiliser sans aucun lien avec un autre code exécutable. Complètement "propre". Les interfaces peuvent également être mélangées.

Mais les classes de base sont utiles pour les implémentations simples et les utilitaires communs. Donc fournissez aussi une classe de base abstraite pour gagner du temps et du code.


105



Les interfaces et les classes de base représentent deux formes différentes de relations.

Héritage (classes de base) représentent une relation "est-un". Par exemple. un chien ou un chat "est-un" animal de compagnie. Cette relation représente toujours le (seul) objectif de la classe (en conjonction avec "principe de responsabilité unique").

Interfaces, d'autre part, représentent caractéristiques supplémentaires d'une classe. Je l'appellerais une relation "est", comme dans "Foo est jetable ", d'où le IDisposable interface en C #.


93



Interfaces

  • Définit le contrat entre 2 modules. Ne peut avoir aucune implémentation.
  • La plupart des langues vous permettent d'implémenter plusieurs interfaces
  • Modifier une interface est un changement de rupture. Toutes les implémentations doivent être recompilées / modifiées.
  • Tous les membres sont publics. Les implémentations doivent implémenter tous les membres.
  • Les interfaces aident au découplage. Vous pouvez utiliser des cadres fictifs pour simuler quoi que ce soit derrière une interface
  • Les interfaces indiquent normalement une sorte de comportement
  • Les implémentations d'interface sont découplées / isolées les unes des autres

Classes de base

  • Vous permet d'ajouter quelques défaut la mise en œuvre que vous obtenez gratuitement par dérivation
  • Sauf C ++, vous ne pouvez dériver que d'une classe. Même si cela peut être de plusieurs classes, c'est généralement une mauvaise idée.
  • Changer la classe de base est relativement facile. Les dérivations n'ont pas besoin de faire quelque chose de spécial
  • Les classes de base peuvent déclarer des fonctions protégées et publiques accessibles par des dérivations
  • Résumé Les classes de base ne peuvent pas être facilement manipulées comme des interfaces
  • Les classes de base indiquent normalement la hiérarchie de type (IS A)
  • Les dérivations de classe peuvent dépendre d'un comportement de base (avoir une connaissance complexe de l'implémentation parente). Les choses peuvent être désordonnées si vous faites un changement à la mise en œuvre de base pour un gars et briser les autres.

57



En général, vous devriez privilégier les interfaces plutôt que les classes abstraites. Une raison d'utiliser une classe abstraite est si vous avez une implémentation commune parmi les classes concrètes. Bien sûr, vous devriez toujours déclarer une interface (IPet) et avoir une classe abstraite (PetBase) implémenter cette interface. En utilisant de petites interfaces distinctes, vous pouvez utiliser des multiples pour améliorer encore la flexibilité. Les interfaces permettent le maximum de flexibilité et de portabilité des types à travers les frontières. Lorsque vous passez des références à travers les frontières, passez toujours l'interface et non le type concret. Cela permet à l'extrémité réceptrice de déterminer la mise en œuvre concrète et offre une flexibilité maximale. Ceci est absolument vrai lors de la programmation dans un mode TDD / BDD.

Le Gang des Quatre a déclaré dans son livre "Parce que l'héritage expose une sous-classe aux détails de la mise en œuvre de ses parents, on dit souvent que" l'héritage rompt l'encapsulation ". Je crois que c'est vrai.


56



C'est assez .NET spécifique, mais le livre de directives de conception de cadre soutient que les classes générales donnent plus de flexibilité dans un cadre évolutif. Une fois qu'une interface est expédiée, vous n'avez pas la possibilité de la changer sans casser le code qui a utilisé cette interface. Avec une classe cependant, vous pouvez le modifier et ne pas casser le code qui y est lié. Tant que vous faites les bonnes modifications, ce qui inclut l'ajout de nouvelles fonctionnalités, vous serez en mesure d'étendre et de faire évoluer votre code.

Krzysztof Cwalina dit à la page 81:

Au cours des trois versions de .NET Framework, j'ai parlé de cette directive avec quelques développeurs de notre équipe. Beaucoup d'entre eux, y compris ceux qui étaient initialement en désaccord avec les lignes directrices, ont dit qu'ils regrettent d'avoir livré une interface API. Je n'ai jamais entendu parler d'un seul cas où quelqu'un aurait regretté d'avoir envoyé un cours.

Cela étant dit, il y a certainement une place pour les interfaces. En règle générale, fournissez toujours une implémentation abstraite de la classe de base d'une interface si ce n'est pour rien d'autre comme un exemple d'implémentation de l'interface. Dans le meilleur des cas, cette classe de base permettra d'économiser beaucoup de travail.


46



Juan,

J'aime penser aux interfaces comme un moyen de caractériser une classe. Une classe de race de chien particulière, disons un YorkshireTerrier, peut être une descendante de la classe de chien parent, mais elle implémente aussi IFurry, IStubby, et IYippieDog. Donc la classe définit ce qu'est la classe mais l'interface nous en dit des choses.

L'avantage est que cela me permet, par exemple, de rassembler tous les IYippieDog et de les jeter dans ma collection Ocean. Alors maintenant je peux atteindre un ensemble d'objets particulier et trouver ceux qui répondent aux critères que je regarde sans trop inspecter la classe.

Je trouve que les interfaces devraient vraiment définir un sous-ensemble du comportement public d'une classe. Si elle définit tout le comportement public pour toutes les classes qui l'implémentent, elle n'a généralement pas besoin d'exister. Ils ne me disent rien d'utile.

Cette pensée va cependant à l'encontre de l'idée que chaque classe devrait avoir une interface et que vous devriez coder à l'interface. C'est bien, mais vous vous retrouvez avec beaucoup d'interfaces individuelles vers les classes et cela rend les choses confuses. Je comprends que l'idée est que cela ne coûte vraiment rien à faire et maintenant vous pouvez échanger des choses avec facilité. Cependant, je trouve que je le fais rarement. La plupart du temps, je ne fais que modifier la classe existante et avoir exactement les mêmes problèmes que ceux que j'ai toujours rencontrés si l'interface publique de cette classe doit changer, sauf que je dois maintenant la changer à deux endroits.

Donc, si vous pensez comme moi, vous direz certainement que chat et chien sont IPettable. C'est une caractérisation qui les associe tous les deux.

L'autre partie de ceci est cependant devrait-ils avoir la même classe de base? La question est de savoir s'ils doivent être traités de la même manière. Certes, ils sont tous deux des animaux, mais cela correspond-il à la façon dont nous allons les utiliser ensemble.

Dites que je veux rassembler toutes les classes d'animaux et les mettre dans mon récipient Ark.

Ou ont-ils besoin d'être des mammifères? Peut-être avons-nous besoin d'une sorte d'usine de traite des animaux?

Ont-ils même besoin d'être liés ensemble? Est-ce suffisant de savoir qu'ils sont tous les deux IPettable?

Je ressens souvent le désir de dériver une hiérarchie de classe entière quand j'ai vraiment juste besoin d'une classe. Je le fais en anticipation un jour je pourrais en avoir besoin et d'habitude je ne le fais jamais. Même quand je le fais, je trouve habituellement que je dois faire beaucoup pour le réparer. C'est parce que le premier cours que je crée n'est pas le chien, je ne suis pas chanceux, mais plutôt l'ornithorynque. Maintenant, toute ma hiérarchie de classe est basée sur le cas bizarre et j'ai beaucoup de code gaspillé.

Vous pouvez également trouver à un certain point que tous les chats ne sont pas IPettable (comme celui glabre). Vous pouvez maintenant déplacer cette interface vers toutes les classes dérivées qui correspondent. Vous constaterez qu'un changement beaucoup moins brusque que tout à coup les chats ne sont plus dérivés de PettableBase.


19



Voici la définition basique et simple de l'interface et de la classe de base:

  • Classe de base = héritage d'objet.
  • Interface = héritage fonctionnel.

à votre santé


15