Encapsulation, Héritage et Polymorphisme en C#
Apprenez l’encapsulation, l’héritage et le polymorphisme en C# avec des exemples pour maîtriser les bases de la POO.
La Programmation Orientée Objet (POO / OOP) est une approche développée pour écrire du code réutilisable, maintenable et compréhensible. Les trois piliers fondamentaux de la POO sont :
- Encapsulation → Masquer les données et fournir un accès contrôlé
- Héritage → Transmettre des comportements communs aux sous-classes
- Polymorphisme → La même méthode se comporte différemment selon l’objet
Lorsque ces trois caractéristiques sont utilisées ensemble, il est possible de construire une architecture solide dans les projets logiciels. Voyons chacune d’elles séparément.
Encapsulation
L’encapsulation cache la structure interne d’une classe au monde extérieur et ne rend accessibles que les parties nécessaires.
Ainsi, la manipulation directe des données est empêchée, les erreurs sont réduites et les changements internes n’affectent pas l’extérieur.
En C#, elle est mise en œuvre avec des modificateurs d’accès tels que private, protected, internal et public.
En général, les champs sont masqués et l’accès contrôlé est fourni via des propriétés ou des méthodes.
public class BankAccount
{
private decimal _balance; // accès direct interdit
public decimal Balance
{
get => _balance;
private set => _balance = value;
}
public void Deposit(decimal amount)
{
if (amount <= 0)
throw new ArgumentException("Le montant doit être supérieur à zéro.");
Balance += amount;
}
public void Withdraw(decimal amount)
{
if (amount > Balance)
throw new InvalidOperationException("Fonds insuffisants.");
Balance -= amount;
}
}
Dans cet exemple, le solde (_balance) ne peut pas être modifié directement.
L’utilisateur ne peut interagir qu’à travers les méthodes Deposit et Withdraw.
Cela empêche une mauvaise utilisation et garantit la sécurité des données.
Héritage
L’héritage permet à une classe d’hériter des propriétés et des comportements d’une autre classe. Ainsi, le code commun est centralisé et devient réutilisable. La classe de base définit les comportements généraux, tandis que les classes dérivées ajoutent des fonctionnalités spécialisées.
public class Animal
{
public string Name { get; set; } = string.Empty;
public void Eat()
{
Console.WriteLine($"{Name} mange.");
}
}
public class Dog : Animal
{
public void Bark()
{
Console.WriteLine($"{Name} aboie.");
}
}
public class Cat : Animal
{
public void Meow()
{
Console.WriteLine($"{Name} miaule.");
}
}
class Program
{
static void Main()
{
Dog d = new Dog { Name = "Rex" };
d.Eat(); // hérité d’Animal
d.Bark(); // spécifique à Dog
Cat c = new Cat { Name = "Minou" };
c.Eat(); // hérité d’Animal
c.Meow(); // spécifique à Cat
}
}
Ici, à la fois Dog et Cat héritent de Animal.
Le comportement commun Eat() est écrit une seule fois mais est disponible dans toutes les sous-classes.
Polymorphisme
Le polymorphisme signifie que la même méthode peut se comporter différemment selon l’objet. Il existe deux types de polymorphisme :
- Polymorphisme à la compilation : Obtenu par surcharge de méthodes (method overloading).
- Polymorphisme à l’exécution : Obtenu grâce aux méthodes
virtualetoverride.
public class Animal
{
public string Name { get; set; } = string.Empty;
public virtual void Speak()
{
Console.WriteLine($"{Name} fait un bruit.");
}
}
public class Dog : Animal
{
public override void Speak()
{
Console.WriteLine($"{Name} aboie.");
}
}
public class Cat : Animal
{
public override void Speak()
{
Console.WriteLine($"{Name} miaule.");
}
}
class Program
{
static void Main()
{
Animal a1 = new Dog { Name = "Rex" };
Animal a2 = new Cat { Name = "Minou" };
a1.Speak(); // Rex aboie.
a2.Speak(); // Minou miaule.
}
}
Le même appel à Speak() produit une sortie différente selon le type de l’objet.
Cette flexibilité est l’un des atouts les plus puissants de la POO.
Exemple : Types de livres
Modélisons des livres dans une application de bibliothèque.
Les propriétés communes sont définies dans la classe Book, tandis que chaque sous-classe ajoute ses propres informations ou
redéfinit la méthode PrintInfo().
De plus, les classes Author et Publisher sont utilisées pour stocker séparément les informations sur l’auteur et l’éditeur.
Cela montre comment l’héritage et le polymorphisme peuvent être combinés.
public class Author
{
public string Name { get; set; } = string.Empty;
public string Country { get; set; } = string.Empty;
}
public class Publisher
{
public string Name { get; set; } = string.Empty;
public string Address { get; set; } = string.Empty;
}
public abstract class Book
{
public string Title { get; set; } = string.Empty;
public Author BookAuthor { get; set; } = new Author();
public Publisher BookPublisher { get; set; } = new Publisher();
public int Pages { get; set; }
public string ISBN { get; set; } = string.Empty;
public int Year { get; set; }
// À personnaliser dans les sous-classes
public abstract void PrintInfo();
}
public class ScienceBook : Book
{
public string Field { get; set; } = string.Empty; // Physique, Chimie, Biologie
public override void PrintInfo()
{
Console.WriteLine($"[Livre scientifique] {Title} - {BookAuthor.Name}, {Pages} pages");
Console.WriteLine($"Domaine : {Field}, ISBN : {ISBN}, Éditeur : {BookPublisher.Name}");
}
}
public class HistoryBook : Book
{
public string Period { get; set; } = string.Empty; // Antiquité, Moyen Âge, etc.
public override void PrintInfo()
{
Console.WriteLine($"[Livre d’histoire] {Title} - {BookAuthor.Name}, {Pages} pages");
Console.WriteLine($"Période : {Period}, ISBN : {ISBN}, Éditeur : {BookPublisher.Name}");
}
}
class Program
{
static void Main()
{
var publisher = new Publisher { Name = "Éditions Savoir", Address = "Paris" };
var author1 = new Author { Name = "Albert Einstein", Country = "Allemagne" };
var author2 = new Author { Name = "Halil Inalcik", Country = "Turquie" };
Book b1 = new ScienceBook
{
Title = "Théorie de la Relativité",
BookAuthor = author1,
BookPublisher = publisher,
Pages = 250,
ISBN = "123-456-789",
Year = 1920,
Field = "Physique"
};
Book b2 = new HistoryBook
{
Title = "L’Empire Ottoman",
BookAuthor = author2,
BookPublisher = publisher,
Pages = 500,
ISBN = "987-654-321",
Year = 1973,
Period = "Période Ottomane"
};
b1.PrintInfo();
Console.WriteLine();
b2.PrintInfo();
}
}
Avantages
- Encapsulation : Garantit la sécurité des données et empêche une mauvaise utilisation.
- Héritage : Réduit la duplication de code et établit une structure hiérarchique.
- Polymorphisme : Permet de créer une architecture flexible et extensible.
TL;DR
- Encapsulation : Masque les données internes et fournit un accès contrôlé.
- Héritage : Les propriétés et comportements de la classe de base sont transmis aux sous-classes.
- Polymorphisme : La même méthode peut se comporter différemment dans différentes sous-classes.
Articles connexes
Classes, Objets, Propriétés et Méthodes en C#
Découvrez comment les classes, objets, propriétés et méthodes en C# constituent les fondements de la programmation orientée objet.
Constructeurs, Destructeurs et this en C#
Apprenez à utiliser les constructeurs, destructeurs et le mot-clé this en C# pour gérer le cycle de vie des objets.
Interfaces et Classes Abstraites en C#
Découvrez les interfaces et classes abstraites en C#, leurs différences et quand les utiliser pour concevoir un code maintenable.
Principes de l’Injection de Dépendances en C#
Apprenez les principes de l’Injection de Dépendances en C#, la gestion des dépendances et le couplage faible avec exemples.
Principes SOLID en C#
Application des principes SOLID en C# avec des exemples : pour un code flexible, maintenable et testable.
Record Types et Objets Immuables en C#
Apprenez les record types et les objets immuables en C#, avec l’égalité par valeur, les with-expressions et des exemples.
Structs en C# – Différences avec les classes
Découvrez les différences entre structs et classes en C#, notamment le modèle mémoire, l’héritage et les performances.