Comment travailler avec le modèle de conception Decorator en C #

Les modèles de conception sont des solutions aux problèmes récurrents et aux complexités de la conception de logiciels et sont classés en trois catégories distinctes: créatives, structurelles et comportementales.

Le modèle de conception Decorator est un modèle structurel et peut être utilisé pour ajouter des fonctionnalités à un objet de manière dynamique sans qu'il soit nécessaire de modifier la structure de l'objet. En substance, vous pouvez tirer parti du modèle Decorator pour attacher des fonctionnalités ou un comportement à un objet de manière dynamique ou statique sans avoir besoin de modifier la structure de l'objet.

Notez que le modèle de conception Decorator suit le principe ouvert fermé, l'un des principes SOLID. Incidemment, le principe ouvert fermé est utilisé pour concevoir des classes ouvertes aux extensions mais fermées aux modifications. La conformité au principe ouvert fermé facilite les applications de construction qui sont réutilisables et peuvent être maintenues facilement. Le Gang of Four (GOF) de Dofactory déclare: "Attachez dynamiquement des responsabilités supplémentaires à un objet. Les décorateurs offrent une alternative flexible au sous-classement pour étendre les fonctionnalités."

Un peu de code

Dans cette section, nous allons explorer comment nous pouvons implémenter le modèle de conception Decorator en C #. Les participants à une mise en œuvre typique du modèle de conception Decorator comprennent:

  1.  Composant - il représente le type de base du type réel ou concret
  2. Composant en béton - il représente le type de béton qui prolonge le composant de base. Notez que les responsabilités ou fonctionnalités supplémentaires sont ajoutées dans ce type.
  3. Décorateur - cela représente une référence à un composant. Les fonctionnalités dynamiques sont ajoutées dans ce type.

Maintenant, considérons la classe suivante.

public abstract class Employee

   {

       public abstract string Display();

   }

Notez que lorsque vous utilisez le modèle de conception Decorator, vous étendez le comportement d'une classe existante, mais cela ne signifie pas nécessairement que vous devez utiliser des types abstraits - les types peuvent ou non être abstraits. Vous pouvez également implémenter le modèle de conception Decorator à l'aide d'interfaces, ou même en utilisant des méthodes virtuelles dans vos classes concrètes. En substance, vous n'êtes pas obligé d'utiliser uniquement des classes abstraites lors de l'implémentation du modèle de conception Decorator. Nous utilisons ici une classe abstraite juste pour des raisons de simplicité.

La classe EmployeeConcrete étend la classe Employee et lui ajoute des propriétés supplémentaires. Voici à quoi ressemblerait cette classe.

   public class EmployeeConcrete : Employee

   {

       public string FirstName { set; get; }

       public string LastName { set; get; }

       public string Address { set; get; }

       public override string Display()

       {

           StringBuilder data = new StringBuilder();

           data.Append("First name: " + FirstName);

            data.Append("\nLast name: " + LastName);

           data.Append("\nAddress: " + Address);

           return data.ToString();

       }

   }

La classe EmployeeDecorator étend la classe Employee, accepte une instance de la classe de composant nommée Employee et remplace la méthode Display (). Voici à quoi ressemblerait cette classe.

public class EmployeeDecorator : Employee

   {

       Employee employee = null;

       protected EmployeeDecorator(Employee employee)

       {

           this.employee = employee;

       }

       public override string Display()

       {

           return employee.Display();

       }

   }

Maintenant que le composant, le composant béton et la classe de décorateur sont prêts, vous pouvez maintenant étendre la classe EmployeeDecorator pour créer une classe de décorateur concret. La liste de code suivante montre à quoi ressemblerait cette classe.

public class PermanentEmployeeDecorator : EmployeeDecorator

   {

       //Add properties relevant to a permanent employee

       private double PF { get; set; }

       public PermanentEmployeeDecorator(Employee employee) : base(employee)

       {   }

       public override string Display()

       {

           return base.Display() + "\nEmployee type: Permanent";

       }

   }

Et c'est tout ce que vous avez à faire! Vous pouvez maintenant créer une instance de PermanentEmployeeDecorator et l'utiliser comme indiqué dans l'extrait de code ci-dessous.

static void Main(string[] args)

       {

           EmployeeConcrete employeeConcrete = new EmployeeConcrete

         { FirstName = "Joydip", LastName = "Kanjilal", Address = "Hyderabad, India" };

           PermanentEmployeeDecorator employeeDecorator = new PermanentEmployeeDecorator(employeeConcrete);

           Console.WriteLine(employeeDecorator.Display());

           Console.Read();

       }

Vous pouvez également avoir un autre type d'employé - un employé contractuel. Pour le représenter, vous devez créer une autre classe nommée ContractEmployeeDecorator qui étend la classe EmployeeDecorator. Reportez-vous à l'extrait de code ci-dessous.

public class ContractEmployeeDecorator : EmployeeDecorator

   {

       //Add properties relevant to a contract employee

       private double RatePerHour { get; set; }

       public ContractEmployeeDecorator(Employee employee) : base(employee)

       { }

       public override string Display()

       {

           return base.Display() + "\nEmployee type: Contractual";

       }

   }

L'extrait de code suivant illustre comment vous pouvez utiliser la classe ContractEmployeeDecorator.

static void Main(string[] args)

       {

           EmployeeConcrete employeeConcrete = new EmployeeConcrete

{ FirstName = "Joydip", LastName = "Kanjilal", Address = "Hyderabad, India" };

           ContractEmployeeDecorator employeeDecorator = new ContractEmployeeDecorator(employeeConcrete);

           Console.WriteLine(employeeDecorator.Display());

           Console.Read();

       }