535 votes

Quand utiliser une interface au lieu d'une classe abstraite et vice versa ?

Il s'agit peut-être d'une question générique sur la POO. Je voulais faire une comparaison générique entre une interface et une classe abstraite sur la base de leur utilisation.

Quand veut-on utiliser une interface et quand veut-on utiliser une classe abstraite ? ?

1 votes

Cette question a été posée à plusieurs reprises : stackoverflow.com/questions/56867/interface-vs-base-class

1 votes

En plus des réponses ci-dessous, voici une courte liste de cas où vous pouvez préférer les interfaces et où vous ne pouvez pas : When To Use Interfaces : msdn.microsoft.com/fr/us/library/3b5b8ezk(v=vs.80).aspx

0 votes

Utilisez abstract quand vous n'êtes pas sûr de ce que la classe va faire. utilisez interface si vous l'êtes.

546voto

Jorge Córdoba Points 18919

J'ai écrit un article à ce sujet :

Classes et interfaces abstraites

Je résume :

Lorsque nous parlons de classes abstraites, nous définissons les caractéristiques d'un type d'objet, en spécifiant les éléments suivants ce qu'est un objet .

Lorsque nous parlons d'une interface et que nous définissons les capacités que nous promettons de fournir, nous parlons de l'établissement d'un contrat concernant ce que l'objet peut faire.

171 votes

C'était très utile : Interfaces do not express something like "a Doberman is a type of dog and every dog can walk" but more like "this thing can walk" . Merci.

2 votes

Il semble que votre lien soit mort.

0 votes

L'explication d'Alex ci-dessous, concernant la différence entre la description des fonctions implémentées et la description de l'état stocké, semble être une meilleure réponse à cette question, car les différences ne sont pas seulement philosophiques.

521voto

Alex Points 6968

Une classe abstraite peut avoir un état ou une fonctionnalité partagée. Une interface est seulement une promesse de fournir l'état ou la fonctionnalité. Une bonne classe abstraite réduira la quantité de code à réécrire car sa fonctionnalité ou son état peut être partagé. L'interface n'a pas d'information définie à partager

83 votes

C'est, à mon avis, la meilleure réponse ici et c'est dommage qu'elle n'ait pas été votée plus haut. Oui, il existe des différences philosophiques entre les deux concepts, mais le point essentiel est que les classes abstraites garantissent que tous les descendants partagent la fonctionnalité/l'état, alors qu'une interface ne garantit qu'un lien commun.

5 votes

Par exemple, une classe de base abstraite est utilisée pour l'élément modèle de méthode alors qu'une interface est utilisée pour le modèle de conception de la stratégie modèle de conception.

2 votes

Je pense que le résumé de Jorge explique la pensée primaire derrière l'existence pour les deux, tandis que la réponse d'Alex est la différence dans les résultats. J'aimerais pouvoir marquer les deux réponses comme étant les bonnes, mais je préfère toujours la réponse de Jorge.

85voto

Paul Hollingsworth Points 4257

Personnellement, je n'ai presque jamais besoin d'écrire des classes abstraites.

La plupart du temps, je vois des classes abstraites (mal) utilisées, c'est parce que l'auteur de la classe abstraite utilise le modèle de la "méthode modèle".

Le problème avec la "méthode modèle" est qu'elle est presque toujours quelque peu ré-entrante - la classe "dérivée" connaît non seulement la méthode "abstraite" de sa classe de base qu'elle implémente, mais aussi les méthodes publiques de la classe de base, même si la plupart du temps elle n'a pas besoin de les appeler.

Exemple (excessivement simplifié) :

abstract class QuickSorter
{
    public void Sort(object[] items)
    {
        // implementation code that somewhere along the way calls:
        bool less = compare(x,y);
        // ... more implementation code
    }
    abstract bool compare(object lhs, object rhs);
}

Ainsi, ici, l'auteur de cette classe a écrit un algorithme générique et souhaite que les gens l'utilisent en le "spécialisant" en fournissant leurs propres "crochets" - dans ce cas, une méthode "compare".

L'utilisation prévue est donc quelque chose comme ceci :

class NameSorter : QuickSorter
{
    public bool compare(object lhs, object rhs)
    {
        // etc.
    }
}

Le problème, c'est que vous avez indûment associé deux concepts :

  1. Une façon de comparer deux éléments (quel élément doit passer en premier)
  2. Une méthode de tri des éléments (c'est-à-dire tri rapide ou tri par fusion, etc.).

Dans le code ci-dessus, théoriquement, l'auteur de la méthode "compare" peut de manière rentrante dans la méthode "Sort" de la superclasse... même si, dans la pratique, ils n'auront jamais envie ou besoin de le faire.

Le prix à payer pour ce couplage inutile est qu'il est difficile de changer la superclasse et, dans la plupart des langages OO, impossible de la changer au moment de l'exécution.

L'autre méthode consiste à utiliser le modèle de conception "Stratégie" à la place :

interface IComparator
{
    bool compare(object lhs, object rhs);
}

class QuickSorter
{
    private readonly IComparator comparator;
    public QuickSorter(IComparator comparator)
    {
        this.comparator = comparator;
    }

    public void Sort(object[] items)
    {
        // usual code but call comparator.Compare();
    }
}

class NameComparator : IComparator
{
    bool compare(object lhs, object rhs)
    {
        // same code as before;
    }
}

Alors remarquez maintenant : Tout ce que nous avons, ce sont des interfaces, et des implémentations concrètes de ces interfaces. En pratique, vous n'avez pas vraiment besoin d'autre chose pour faire une conception OO de haut niveau.

Pour "cacher" le fait que nous avons implémenté le "tri des noms" en utilisant une classe "QuickSort" et un "NameComparator", nous pouvons toujours écrire une méthode de fabrique quelque part :

ISorter CreateNameSorter()
{
    return new QuickSorter(new NameComparator());
}

Tout Dès que vous avez une classe abstraite, vous pouvez le faire... même lorsqu'il existe une relation ré-entrante naturelle entre la classe de base et la classe dérivée, il est généralement utile de les rendre explicites.

Une dernière pensée : Tout ce que nous avons fait ci-dessus est de "composer" une fonction "NameSorting" en utilisant une fonction "QuickSort" et une fonction "NameComparison"... dans un langage de programmation fonctionnel, ce style de programmation devient encore plus naturel, avec moins de code.

7 votes

Ce n'est pas parce que vous pouvez utiliser des classes abstraites ou le modèle Template Method que vous devez les éviter. Le modèle Stratégie est un modèle différent pour une situation différente comme dans cet exemple, mais il y a beaucoup d'exemples où un modèle template est beaucoup plus approprié que Stratégie.

5 votes

Eh bien, d'après mon expérience, je ne les rencontre jamais (situations où la méthode template est préférable)... ou rarement en tout cas. Et c'est tout ce que "abstract" est - un support de langage pour le modèle de conception "méthode template".

0 votes

Ok, je l'ai utilisé une fois pour un système expert où le processus était quelque chose comme, obtenir 1. Remplir les paramètres, 2. faire le produit vectoriel entre eux, 3. pour chaque paire calculer le résultat, 4. joindre les résultats, où les étapes 1 et 3 étaient déléguées et 2 et 4 implémentées dans la classe de base.

50voto

PreethaA Points 360

Mes deux centimes :

Une interface définit essentiellement un contrat auquel toute classe d'implémentation doit adhérer (implémenter les membres de l'interface). Elle ne contient pas de code.

D'autre part, une classe abstraite peut contenir du code, et il peut y avoir certaines méthodes marquées comme abstraites qu'une classe héritière doit mettre en œuvre.

Les rares situations dans lesquelles j'ai utilisé des classes abstraites sont celles où j'ai une fonctionnalité par défaut que la classe héritière ne serait pas intéressée à surcharger, dans une classe de base abstraite, par exemple, dont héritent certaines classes spécialisées.

Exemple (très rudimentaire !) : considérons une classe de base appelée Customer qui possède des méthodes abstraites telles que CalculatePayment() , CalculateRewardPoints() et certaines méthodes non-abstraites comme GetName() , SavePaymentDetails() .

Des cours spécialisés comme RegularCustomer et GoldCustomer héritera de la Customer et implémentent leur propre classe de base CalculatePayment() y CalculateRewardPoints() mais en réutilisant la logique de la méthode GetName() y SavePaymentDetails() méthodes.

Vous pouvez ajouter plus de fonctionnalités à une classe abstraite (c'est-à-dire des méthodes non abstraites) sans affecter les classes enfant qui utilisaient une version plus ancienne. En revanche, l'ajout de méthodes à une interface affecterait toutes les classes qui l'implémentent, car elles devraient désormais implémenter les membres de l'interface nouvellement ajoutée.

Une classe abstraite avec tous les membres abstraits serait similaire à une interface.

2 votes

+1 pour "Vous pouvez ajouter plus de fonctionnalités à une classe abstraite (c'est-à-dire des méthodes non abstraites) sans affecter les classes filles qui utilisaient une version plus ancienne. Alors que l'ajout de méthodes à une interface affecterait toutes les classes qui l'implémentent car elles devraient maintenant implémenter les membres de l'interface nouvellement ajoutée."

1 votes

Les interfaces peuvent avoir des méthodes "par défaut", donc ne pas avoir de méthode impl dans les interfaces est une mauvaise idée. La relation "parent-enfant" IS-A est la clé ici. De même, les "attributs partagés" et les "propriétés partagées". Par exemple, un chien est un animal. Mais un chien peut aussi "marcher".

41voto

sunwukung Points 1173

Je sais que ce sujet est vieux comme le monde, mais quelqu'un d'autre pourrait bien tomber dessus un jour...

Les classes abstraites vous permettent de créer un modèle et de CONSTRUIRE (implémenter) les propriétés et les méthodes que vous souhaitez que TOUS ses descendants possèdent.

Une interface, quant à elle, vous permet seulement de déclarer que vous voulez que les propriétés et/ou les méthodes portant un nom donné existent dans toutes les classes qui l'implémentent - mais ne spécifie pas comment vous devez l'implémenter. En outre, une classe peut mettre en œuvre de NOMBREUSES interfaces, mais ne peut étendre qu'UNE seule classe abstraite. Une interface est davantage un outil architectural de haut niveau (ce qui devient plus clair si vous commencez à comprendre les modèles de conception) - une classe abstraite a un pied dans les deux camps et peut également effectuer une partie du sale boulot.

Pourquoi utiliser l'un plutôt que l'autre ? Le premier permet une plus béton définition des descendants - cette dernière permet une plus grande polymorphisme . Ce dernier point est important pour l'utilisateur final/codeur, qui peut utiliser ces informations pour mettre en œuvre l'A.P. I(nterface) dans une variété de combinaisons/formes pour répondre à leurs besoins.

Je pense que c'est le moment où j'ai eu une révélation : il faut penser aux interfaces moins du point de vue de l'auteur que de celui d'un codeur qui arrive plus tard dans la chaîne et qui ajoute l'implémentation à un projet, ou extension de une API.

0 votes

Pour s'en inspirer : Un objet qui implémente une interface prend le TYPE de celle-ci. C'est crucial. Ainsi, vous pouvez passer différentes variations de l'interface à une classe, mais vous y faites référence (et à leurs méthodes) AVEC LE NOM DU TYPE DE L'INTERFACE. Ainsi, vous éliminez la nécessité d'un commutateur ou d'une boucle if/else. Essayez ce tutoriel sur le sujet - il démontre l'utilisation d'une interface via le Strategy Pattern. phpfreaks.com/tutorial/design-patterns---strategie-et-pont/

0 votes

Je suis tout à fait d'accord avec ton moment d'illumination : "A.P.I(nterface) dans une variété de combinaisons/formes pour répondre à leurs besoins" ! Très très bon point à souligner.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X