Menu
Coddy logo textTech

Composition plutôt qu'héritage

Fait partie de la section Programmation Orientée Objet du Journey C# de Coddy. Leçon 41 sur 70.

L’héritage crée un couplage étroit entre les classes. Lorsqu’une Car hérite de Vehicle, toute modification apportée à Vehicle peut entraîner une défaillance de Car. La composition offre une alternative plus flexible : au lieu d’hériter d’un comportement, une classe contient des objets qui fournissent ce comportement.

Considérez un personnage de jeu qui peut se déplacer et attaquer. Avec l’héritage, vous pourriez créer une hiérarchie complexe. Avec la composition, vous donnez simplement au personnage les composants dont il a besoin :

public class MovementBehavior
{
    public void Move() => Console.WriteLine("Moving...");
}

public class AttackBehavior
{
    public void Attack() => Console.WriteLine("Attacking!");
}

public class Character
{
    private MovementBehavior movement = new MovementBehavior();
    private AttackBehavior attack = new AttackBehavior();
    
    public void Move() => movement.Move();
    public void Attack() => attack.Attack();
}

La différence essentielle réside dans la relation. L’héritage représente « est-un » (un Dog est un Animal), tandis que la composition représente « a-un » (un Character a un comportement de mouvement). La composition vous permet de remplacer les comportements lors de l’exécution, de combiner librement les capacités et d’éviter le problème de la classe de base fragile.

Utilisez l’héritage lorsqu’il existe une véritable relation hiérarchique. Choisissez la composition lorsque vous avez besoin de flexibilité, lorsque des comportements peuvent être partagés entre des classes sans lien, ou lorsque vous souhaitez modifier le comportement dynamiquement.

challenge icon

Défi

Facile

Construisons un système de notifications qui démontre la puissance de la composition par rapport à l'héritage. Au lieu de créer une hiérarchie complexe de classes de notifications, vous composerez un NotificationSender en lui fournissant des composants de comportement interchangeables.

Vous organiserez votre code sur trois fichiers :

  • Behaviors.cs : créez deux classes de comportement dans l'espace de noms Notifications qui gèrent différents aspects de l'envoi de notifications :
    • FormattingBehavior - possède une méthode Format(string message) qui renvoie le message entouré de [ALERT] au début et de [END] à la fin
    • DeliveryBehavior - possède une méthode Deliver(string channel, string message) qui renvoie une chaîne au format Sending via {channel}: {message}
  • NotificationSender.cs : créez une classe NotificationSender dans l'espace de noms Notifications qui utilise la composition pour combiner les comportements. Votre expéditeur doit :
    • contenir des instances de FormattingBehavior et de DeliveryBehavior en tant que champs privés
    • posséder une propriété Channel (string) qui stocke le nom du canal de livraison
    • posséder un constructeur qui accepte le nom du canal
    • posséder une méthode Send(string message) qui commence par formater le message à l'aide du comportement de formatage, puis le distribue à l'aide du comportement de livraison, et renvoie le résultat final
  • Program.cs : dans votre fichier principal, créez un NotificationSender avec un canal fourni en entrée, puis envoyez un message fourni en entrée. Affichez le résultat pour montrer comment les comportements composés fonctionnent ensemble.

Vous recevrez deux entrées :

  • le nom du canal de livraison (par exemple, Email, SMS)
  • le message à envoyer

Affichez le résultat de l'appel à Send() sur votre expéditeur de notifications.

Par exemple, si les entrées sont Email et Server is down, la sortie doit être :

Sending via Email: [ALERT] Server is down [END]

Remarquez que NotificationSender n'hérite de rien : il « possède » simplement des comportements de formatage et de livraison. Cette approche par composition signifie que vous pourriez facilement remplacer l'un ou l'autre comportement sans modifier la classe d'expédition, ou réutiliser ces comportements dans des classes complètement différentes !

Essayez vous-même

using System;
using Notifications;

class Program
{
    public static void Main(string[] args)
    {
        // Lire l'entrée
        string channel = Console.ReadLine();
        string message = Console.ReadLine();

        // TODO: Créer un NotificationSender avec le channel
        
        // TODO: Envoyer le message et afficher le résultat
        
    }
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet

Entraînez-vous par vous-même : Compilateur C# en ligne