web-dev-qa-db-fra.com

Comment choisir entre une interface ou une classe de base pour une nouvelle implémentation?

En ce qui concerne l'implémentation, comment devrais-je choisir un type de base ou une interface? J'ai essayé de travailler sur quelques exemples mais je ne comprends pas l'idée complète :(

Des exemples sur comment et pourquoi seraient grandement appréciés.

28
Sakthivel

Une classe de base, abstraite ou non, peut contenir des membres implémentés. Une interface ne peut pas. Si toutes vos implémentations fonctionnent de la même manière, une classe de base pourrait s'avérer être la solution, car toutes vos classes enfants peuvent partager les mêmes implémentations des membres de la classe de base. S'ils ne vont pas partager les implémentations, alors une interface pourrait être la solution.

Exemple:

class Person
{
    string Name { get; set; }
}

class Employee : Person
{
    string Company { get; set; }
}

Il est logique que Employee hérite de Person car la classe Employee ne doit pas définir de propriété Name car elle partage l'implémentation.

interface IPolygon
{
    double CalculateArea()
}

class Rectangle : IPolygon
{
    double Width { get; set; }
    double Height { get; set; }

    double CalculateArea()
    {
        return this.Width * this.Height;
    }
}

class Triangle : IPolygon
{
    double Base { get; set; }
    double Height { get; set; }

    double CalculateArea()
    {
        return 0.5 * this.Base * this.Height;
    }
}

Étant donné que Rectangle et Triangle ont des implémentations aussi différentes de CalculateArea, il n’a aucun sens de leur faire hériter d’une classe de base.

Si vous créez une classe de base et constatez que dans only contient des membres abstraits, vous pouvez également simplement utiliser une interface.

Et, comme le dit j__m, vous ne pouvez pas hériter de plusieurs classes de base, mais vous pouvez implémenter plusieurs interfaces.

D'habitude, je définis d'abord les interfaces, et si je me trouve en train de dupliquer du code dans mes implémentations, je crée une classe de base qui l'implémente et en hérite.

39
Dan

Pour décider d’utiliser une classe abstraite ou une interface, je trouve cet article très utile Source :

Un bon moyen de distinguer un cas pour l’un ou l’autre a toujours été le suivant:

  1. Existe-t-il de nombreuses classes pouvant être "regroupées" et décrites par un nom? Si c'est le cas, ayez une classe abstraite portant le nom de ce nom et héritez-en des classes. (Un facteur clé est que ces classes partagent des fonctionnalités et que vous n'instancieriez jamais juste un Animal ... vous instancieriez toujours un certain type de Animal: une implémentation de votre base Animal. classe) Exemple: Cat et Dog peuvent tous deux hériter de la classe abstraite Animal, et cette classe de base abstraite implémentera une méthode void Breathe () à laquelle tous les animaux feront donc exactement la même chose. (Je pourrais rendre cette méthode virtuelle afin de pouvoir la remplacer pour certains animaux, comme Fish, qui ne respire pas comme la plupart des animaux).

  2. Quels types de verbes peuvent être appliqués à ma classe, ce qui pourrait en général être aussi appliqué à d'autres? Créez une interface pour chacun de ces verbes . Exemple: Tous les animaux peuvent être nourris. Je vais donc créer une interface appelée IFeedable et laisser Animal le mettre en œuvre. Seuls Dog et Horse sont suffisamment pratiques pour implémenter ILikeable - je ne l'implémenterai pas dans la classe de base, car cela ne s'applique pas à Cat.

S'il vous plaît également regarder cette Interface vs classe de base question.

18
Alina B.

L'une des raisons d'utiliser les classes abstraites est lorsque nous devons imposer une initialisation (comme les états via le constructeur).

L'interface ne vous permet pas de définir les contrats du constructeur.

Dans l'exemple ci-dessous, chaque objet Animal DEVRAIT avoir un NOM. Cela ne peut pas être appliqué via une interface.

public abstract class Animal
{
    public Animal(string name)
    {
        this.Name = name;
    }

    public string Name 
    { 
        get; 
        private set; 
    }
}

public class Cat : Animal
{
    public Cat(string name)
        : base(name)
    {

    }

    string NoOfLegs { get; set; }
}



class Program
{
    static void Main(string[] args)
    {
        Animal aCat = new Cat("a");
    }
}
4
jacob aloysious

En réalité, ils ne sont pas nécessairement mutuellement exclusifs. Vous pouvez utiliser les deux en fonction de l'évolution de l'implémentation de votre code.

Une interface est généralement l’énonciation d’un contrat. Il définit un comportement attendu, que les développeurs doivent respecter. Et il est généralement considéré comme une bonne pratique de coder votre api public contre interfaces . Ainsi, vous réduisez le couplage aux détails de vos implémentations et permettez une refactorisation et une maintenance plus faciles de votre code. Maintenant, ce qui est qualifié d’API publique, ce sont les composants logiciels qui intègrent l’interaction de haut niveau définie dans votre conception et qui sont destinés à être réutilisés par vous-même et d’autres personnes dans le même projet ou dans plusieurs projets de portée indépendante.

Une classe de base fait déjà partie de la implémentation . Qu'il implémente une interface ou non. Et il relie sa hiérarchie potentielle à des détails d’implémentation spécifiques: état de l’objet, méthodes pouvant être surchargées ou non, etc.

3
ylabidi

Les interfaces sont une construction plus flexible. Vous ne pouvez avoir qu'une seule classe de base, mais vous pouvez implémenter plusieurs interfaces. Si vous avez besoin d'un objet pour prendre en charge plusieurs comportements, mais que plusieurs de ces comportements nécessitent une classe de base spécifique, vous ne pourrez pas le faire.

Comme Dan note, les classes de base ont un avantage pratique dans de nombreuses langues en ce sens que vous pouvez fournir une implémentation de base. Pour ce faire avec une interface, vous devez créer une classe fournissant l'implémentation de base, puis déléguer manuellement l'implémentation de chaque méthode d'interface à cette classe - ce qui est moins pratique.

2
j__m

Je trouve une analogie aide ici:

Classe de base abstraite: - Un constructeur automobile peut développer un moteur à essence présentant certaines variantes (1.6, 2L, etc.). La conversion de bloc moteur peut être considérée comme la classe de base abstraite, c’est-à-dire qu’elle définit la forme de base et les caractéristiques du moteur. Une version 2L peut avoir une plus grande culasse, etc. 

Interfaces: - Le moteur peut également utiliser divers composants du commerce, par exemple: alternateur, radiateur, démarreur, etc. et doit donc implémenter interfaces définies par ces composants. Ces composants ont généralement été conçus sans connaître les moteurs qui peuvent les utiliser.

1
Adrian