CodeGym /Cours /C# SELF /Abstractions dans la construction des hiérarchies

Abstractions dans la construction des hiérarchies

C# SELF
Niveau 22 , Leçon 3
Disponible

1. Introduction

On va essayer de mater l'abstraction avec un peu de recul : imagine un grand bureau où différents employés font des tâches différentes. Ils peuvent tous avoir le même poste — "Employé", mais chacun a sa mission spéciale. Mais si toi, en tant que boss, tu veux que chaque employé puisse "EffectuerTravail", tu t'en fiches de comment c'est fait : le dev code, le comptable tape des rapports. Cette idée de "contrat général pour tout le monde via l'abstraction, les détails — pour les spécialistes" c'est la base pour bien construire une hiérarchie de classes.

Ça donne quoi dans le code ?

Tout commence avec une classe abstraite de base. Elle décrit le plus important que tous ses héritiers doivent savoir faire.


public abstract class Employe
{
    public string Nom { get; }
    public Employe(string nom)
    {
        Nom = nom;
    }

    // Méthode abstraite — contrat pour tous les employés
    public abstract void EffectuerTravail();
}

Ensuite viennent les classes dérivées (héritiers) — développeur et comptable :


public class Programmeur : Employe
{
    public Programmeur(string nom) : base(nom) { }
    public override void EffectuerTravail()
    {
        Console.WriteLine($"{Nom} écrit du code");
    }
}

public class Comptable : Employe
{
    public Comptable(string nom) : base(nom) { }
    public override void EffectuerTravail()
    {
        Console.WriteLine($"{Nom} compte l'argent");
    }
}

Maintenant regarde : on peut créer une liste d'employés — que ce soit des comptables, des devs, ou qui tu veux (l'abstraction s'en fiche complètement !).


Employe[] bureau = new Employe[]
{
    new Programmeur("John"),
    new Comptable("Jane")
};

foreach (Employe emp in bureau)
{
    emp.EffectuerTravail(); // Chacun fait son taf
}

John écrit du code
Jane compte l'argent

Tu vois comme tout est devenu propre, universel et surtout évolutif. Tu peux ajouter une nouvelle classe, genre Manager, et le code déjà écrit — pas besoin d'y toucher !

2. Comment construire des hiérarchies sur la base des abstractions

Vu que quasi tous les bouquins d'OOP ne peuvent pas vivre sans l'exemple des animaux, on va faire pareil.

Classe abstraite — en mode "Grand Dictateur"


public abstract class Animal
{
    public string Nom { get; set; }
    public Animal(string nom)
    {
        Nom = nom;
    }

    // Tous les animaux doivent savoir faire un bruit
    public abstract void FaireBruit();

    // Mais pas obligé de savoir voler, donc :
    public virtual void Voler()
    {
        Console.WriteLine("Je ne peux pas voler.");
    }
}

Classes enfants : obligées de faire du bruit, peuvent override d'autres méthodes aussi


public class Chat : Animal
{
    public Chat(string nom) : base(nom) { }
    public override void FaireBruit()
    {
        Console.WriteLine($"{Nom}: Miaou !");
    }
}

public class Chien : Animal
{
    public Chien(string nom) : base(nom) { }
    public override void FaireBruit()
    {
        Console.WriteLine($"{Nom}: Ouaf !");
    }
}

public class Aigle : Animal
{
    public Aigle(string nom) : base(nom) { }
    public override void FaireBruit()
    {
        Console.WriteLine($"{Nom}: Cri !");
    }

    public override void Voler()
    {
        Console.WriteLine($"{Nom} vole dans le ciel !");
    }
}

Et maintenant, on va faire une collection d'animaux différents :


Animal[] zoo = new Animal[]
{
    new Chat("Whiskers"),
    new Chien("Spot"),
    new Aigle("Eagle")
};

foreach (Animal animal in zoo)
{
    animal.FaireBruit();
    animal.Voler();
}

Whiskers: Miaou !
Je ne peux pas voler.
Spot: Ouaf !
Je ne peux pas voler.
Eagle: Cri !
Eagle vole dans le ciel !

Tu vois comme c'est simple d'utiliser n'importe quelle classe héritière : on ne se demande pas quel objet est dans la collection. L'abstraction s'occupe du "contrat", et les détails d'implémentation — du comportement concret.

3. Abstraction sur plusieurs niveaux

L'abstraction, ce n'est pas juste séparer une classe de base et ses héritiers directs. Dans les systèmes complexes, souvent c'est sur plusieurs niveaux, où une classe abstraite est basée sur une autre. C'est comme un millefeuille (ou un oignon, comme dirait Shrek) : chaque couche cache des détails en trop, et ne laisse que l'essentiel.

Exemple : Hiérarchie des moyens de transport


.              Vehicule (abstract)
            /           |           \
       Voiture        Avion        Bateau
  VoitureElectrique  AvionJet    Voilier

Ici Vehicule pose les principes généraux (genre la méthode Deplacer()), mais ne sait pas comment une voiture ou un avion va bouger. Ça, c'est les classes dérivées qui gèrent. Les classes plus concrètes, comme VoitureElectrique ou AvionJet, peuvent rajouter leurs propres trucs, pour plus de fonctionnalités.

Schéma de la hiérarchie :


.       +------------------+
        |  Vehicule        |  <--- classe abstraite
        +------------------+
        /        \
   +-------+   +-------+
   | Voiture|  | Bateau|  <--- abstractions intermédiaires ou classes concrètes
   +-------+   +-------+

Code : classe abstraite de base


public abstract class Vehicule
{
    public string Modele { get; }
    public Vehicule(string modele)
    {
        Modele = modele;
    }

    // Méthode abstraite
    public abstract void Deplacer();
}

Classe abstraite intermédiaire

Parfois, au niveau intermédiaire, il faut aussi des abstractions !


public abstract class Voiture : Vehicule
{
    public Voiture(string modele) : base(modele) { }

    public override void Deplacer()
    {
        Console.WriteLine($"{Modele} roule sur la route.");
    }

    // Méthode abstraite — toutes les voitures ne sont pas électriques :
    public abstract void RavitaillerOuCharger();
}

Implémentations concrètes


public class VoitureElectrique : Voiture
{
    public VoitureElectrique(string modele) : base(modele) { }

    public override void RavitaillerOuCharger()
    {
        Console.WriteLine($"{Modele} se recharge à l'électricité.");
    }
}

public class VoitureEssence : Voiture
{
    public VoitureEssence(string modele) : base(modele) { }

    public override void RavitaillerOuCharger()
    {
        Console.WriteLine($"{Modele} fait le plein d'essence.");
    }
}

Résultat : l'abstraction sur plusieurs niveaux rend l'ajout de nouvelles classes et fonctionnalités super facile.

Visualisation : exemple de hiérarchie de classes

Classe Type Abstraite Parent Comportement spécial
Vehicule De base Oui - Méthode abstraite Deplacer()
Voiture Intermédiaire Oui Vehicule Abstraite RavitaillerOuCharger()
VoitureElectrique Finale Non Voiture Implémentation RavitaillerOuCharger()
VoitureEssence Finale Non Voiture Implémentation RavitaillerOuCharger()
Bateau Finale Non Vehicule Implémentation Deplacer()

4. Utiliser l'abstraction pour des applis évolutives

À quoi ça sert concrètement :

  1. Flexibilité et évolutivité du code : Tu peux ajouter une nouvelle classe (genre un nouveau type d'animal, de véhicule ou d'employé), sans toucher au code déjà écrit. Tes boucles/méthodes vont marcher avec le nouvel objet direct — tant qu'il implémente les méthodes définies dans l'abstraction.
  2. Moins de duplication de code : Les propriétés et méthodes communes (genre nom, logique de base) sont définies une fois dans la classe abstraite, et les héritiers les récupèrent automatiquement.
  3. Super courant dans les gros frameworks et systèmes : Par exemple, dans ASP.NET MVC t'as des contrôleurs de base abstraits (ControllerBase), et dans WinForms — la classe abstraite Control pour tous les éléments UI. Ça permet d'étendre le framework sans casser ce qui existe déjà.

Où ça sert ?

  • Tous les gros systèmes : applis bancaires (employés, opérations et transactions), jeux (entités de jeu, persos), applis business (catalogues, produits, utilisateurs), toutes les données hiérarchiques ou structurées.
  • Entretiens techniques : savoir construire des classes sur la base d'abstractions et expliquer les hiérarchies — question classique en entretien.
  • Architecture logicielle : l'abstraction permet de poser le "squelette" de l'archi avant même d'écrire la logique — super pratique pour le dev en équipe, le TDD (développement piloté par les tests) et juste pour la maintenabilité.

5. Erreurs classiques et pièges dans la construction des hiérarchies

Erreur n°1 : oubli d'implémenter une méthode abstraite.
Le compilateur ne te laissera pas créer une instance d'une classe dérivée si elle n'implémente pas tous les membres abstraits de la classe de base. C'est la règle — genre loi non écrite : tu veux être concret — tu implémentes tout.

Erreur n°2 : essayer d'hériter de plusieurs classes abstraites.
En C#, tu ne peux pas hériter de plusieurs classes à la fois, même si elles sont toutes abstraites. C'est une limite du langage. Si tu veux "hériter" de plusieurs sources — utilise des interfaces. C'est comme des classes abstraites, mais plus light et sans implémentation.

Erreur n°3 : ne pas piger l'intérêt des classes abstraites intermédiaires.
Ces classes servent souvent à regrouper de la logique commune et à empêcher la création d'objets "pas assez définis". Par exemple, la classe Voiture peut être abstraite pour éviter que quelqu'un crée juste une "voiture" sans préciser si elle est à essence, diesel ou électrique.

2
Mission
C# SELF, niveau 22, leçon 3
Bloqué
Création d'une hiérarchie de classes avec une classe abstraite
Création d'une hiérarchie de classes avec une classe abstraite
2
Mission
C# SELF, niveau 22, leçon 3
Bloqué
Abstraction multiniveau : véhicules
Abstraction multiniveau : véhicules
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION