Initialisation des systèmes...

Baptiste.Dev
Retour aux notes
LangagesIntermédiaireSérie : C# / .NET

C# : Les interfaces

Contrats, implémentation multiple, polymorphisme - comment les interfaces structurent le code en C#.

4 min de lecture
Mis à jour il y a 4 mois
c#csharpinterfacepolymorphismePOOcontrat

C# : Les interfaces

Dans l'article sur les objets, on a vu que l'héritage permet de réutiliser du code, mais qu'une classe ne peut hériter que d'une seule classe parent. Les interfaces résolvent cette limitation.


# Qu'est-ce qu'une interface ?

Une interface est un contrat. Elle définit un ensemble de méthodes et propriétés qu'une classe doit implémenter, sans dire comment.

interface IVehicule
{
    string Marque { get; }
    void Demarrer();
    void Arreter();
}

Pas de code dans les méthodes, pas de constructeur, pas de champs - juste des signatures. L'interface dit quoi, la classe dit comment.

Par convention en C#, les noms d'interfaces commencent toujours par un I majuscule : IVehicule, IDisposable, IEnumerable.


# Implémenter une interface

Une classe qui implémente une interface doit fournir le code de chaque membre déclaré :

class Voiture : IVehicule
{
    public string Marque { get; }
 
    public Voiture(string marque)
    {
        Marque = marque;
    }
 
    public void Demarrer()
    {
        Console.WriteLine($"{Marque} démarre");
    }
 
    public void Arreter()
    {
        Console.WriteLine($"{Marque} s'arrête");
    }
}

Si tu oublies d'implémenter Arreter(), le compilateur refuse de compiler. Le contrat est strict.


# Implémentation multiple

Contrairement à l'héritage (limité à un seul parent), une classe peut implémenter autant d'interfaces qu'elle veut :

interface IVehicule
{
    void Demarrer();
    void Arreter();
}
 
interface IElectrique
{
    int Autonomie { get; }
    void Recharger();
}
 
interface IConnecte
{
    void SynchroniserGPS();
}
 
class TeslaModelS : IVehicule, IElectrique, IConnecte
{
    public int Autonomie { get; } = 600;
 
    public void Demarrer() => Console.WriteLine("Tesla démarre silencieusement");
    public void Arreter() => Console.WriteLine("Tesla s'arrête");
    public void Recharger() => Console.WriteLine("Recharge en cours...");
    public void SynchroniserGPS() => Console.WriteLine("GPS synchronisé");
}

TeslaModelS respecte trois contrats en même temps. C'est la force des interfaces - elles permettent de composer des comportements sans les contraintes de l'héritage.


# Polymorphisme avec les interfaces

Le vrai pouvoir des interfaces, c'est le polymorphisme : traiter des objets différents de manière uniforme via leur contrat commun.

void FaireLeTrajet(IVehicule vehicule)
{
    vehicule.Demarrer();
    Console.WriteLine("En route...");
    vehicule.Arreter();
}
 
Voiture peugeot = new Voiture("Peugeot");
Velo monVelo = new Velo();  // implémente aussi IVehicule
 
FaireLeTrajet(peugeot);   // fonctionne
FaireLeTrajet(monVelo);   // fonctionne aussi

La méthode FaireLeTrajet ne sait pas si c'est une voiture ou un vélo - elle sait juste que l'objet a Demarrer() et Arreter(). C'est ça le polymorphisme : le même code fonctionne avec des types différents.


# Implémentation par défaut (C# 8+)

Depuis C# 8, les interfaces peuvent fournir une implémentation par défaut pour certaines méthodes. Les classes qui implémentent l'interface n'ont pas besoin de la redéfinir, mais elles peuvent le faire.

interface ILogger
{
    void Log(string message);
 
    // Implémentation par défaut
    void LogError(string message)
    {
        Log($"[ERREUR] {message}");
    }
}
 
class ConsoleLogger : ILogger
{
    public void Log(string message)
    {
        Console.WriteLine(message);
    }
    // LogError est déjà implémenté par l'interface
}

C'est utile pour ajouter des méthodes à une interface existante sans casser toutes les classes qui l'implémentent déjà.


# Interface vs classe abstraite

La question revient souvent : quand utiliser quoi ? (Voir l'article sur les classes abstraites pour les détails.)

InterfaceClasse abstraite
Héritage multipleOui (autant qu'on veut)Non (un seul parent)
ChampsNonOui
ConstructeurNonOui
ImplémentationPar défaut uniquement (C# 8+)Partielle ou complète
Quand l'utiliserDéfinir un contrat communPartager du code commun

La règle simple : si tu veux juste définir "ce qu'un objet sait faire" -> interface. Si tu veux aussi fournir du code partagé entre les enfants -> classe abstraite.


# La suite

  • Les structs - value types personnalisés, différence avec les classes
  • Les records - immutabilité et comparaison par valeur
  • Les enums - énumérations et constantes nommées