Le design pattern Adapter

Dans notre article précédent sur l’Abstract Factory, nous vous avons présenté le principe et l’intérêt des Design Patterns. Dans cet article, nous allons poursuivre notre présentation des patterns de structure par le design pattern Adapter.

Présentation

Le pattern “Adapter” permet de faire rentrer des ronds dans des carrés, de ranger les torchons avec les serviettes et de mélanger les choux et les carottes. A peu près. L’objectif est de faire dialoguer un élément hétérogène de notre système avec des éléments homogènes. Et ce, sans perturber le fonctionnement du reste de l’application.

Prenons un cas concret. Nous sommes un grossiste et vendons des articles à de grandes enseignes de la grande distribution. Nous avons une application mise à disposition de ces clients pour acheter nos articles. Tous nos clients sont homogènes, car ils implémentent l’interface IUtilisateur. Cette application est également ouverte à nos salariés qui souhaitent se fournir directement chez nous, sans passer par la grande distribution.

Un jour, nous avons eu à faire évoluer une fonctionnalité de notre application : lister l’ensemble de nos clients, mais cette fois en indiquant pour les employés leur poste actuel.

Notre problème est le suivant : Nous avons une gestion identique des clients et des salariés et nous ne voulons pas refaire entièrement la gestion des utilisateurs et souhaitons que cette évolution ne perturbe pas le fonctionnement actuel de l’application.

Pour y répondre, nous faisons le choix d’utiliser le pattern “Adapter”, pour que l’appel de la méthode “AfficherUtilisateur” nous affiche le nom du client, et dans le cas d’un employé son nom suivi de son poste actuel.

Nous avons créé une application console pour illustrer ce cas. Elle crée une liste de clients et, pour chacun d’eux, appelle la méthode “AfficherUtilisateur”. S’il s’agit d’un client, on affiche son nom, s’il s’agit d’un employé, son nom suivi de son poste.

Voici le modèle de classes :

Adapter

Nous voyons ici que nous avons mappé la classe Employe à l’aide de la classe EmployeAdapter, qui hérite de IUtilisateur.

Implémentation

Code

public interface IUtilisateur
{
    void AfficherUtilisateur();
}

public class Client : IUtilisateur
{
    private string _nom;

    public Client(string nom)
    {
        _nom = nom;
    }
    public void AfficherUtilisateur()
    {
        Console.WriteLine("Nom du client : {0}", _nom);
    }
}

public class Employe
{
    private string _nom;
    private string _poste;

    public Employe(string nom, string poste)
    {
        _nom = nom;
        _poste = poste;
    }
    public void AfficherNom()
    {
        Console.WriteLine("Nom de l'employé : {0}", _nom);
    }
    public void AfficherPoste()
    {
        Console.WriteLine("-> Poste actuel : {0}", _poste);
    }
}

public class EmployeAdapter : IUtilisateur
{
    private Employe _employe;

    public EmployeAdapter(Employe employe)
    {
        _employe = employe;
    }
    public void AfficherUtilisateur()
    {
        _employe.AfficherNom();
        _employe.AfficherPoste();
    }
}

class Program
{
    static void Main(string[] args)
    {
        List list = new List();
        list.Add(new Client("Tom"));
        Employe employe = new Employe("Jerry", "Vendeur de fromage");
        list.Add(new EmployeAdapter(employe));
        AfficherUtilisateurs(list);
    }
    static void AfficherUtilisateurs(List list)
    {
        foreach (IUtilisateur utilisateur in list)
        {
            utilisateur.AfficherUtilisateur();
        }
    }
}

Resultat :

Nom du client : Tom
Nom de l'employé : Jerry
Poste actuel : Vendeur de fromage

Conclusion

Dans le cadre de vos développements, vous avez probablement déjà été confronté à une de ces situations où :

– une classe implémentée et utilisée dans diverses parties de votre application doit avoir, à un endroit bien précis, un comportement différent sans pour autant en modifier son comportement initial,

– vous ne voulez pas développer toutes les méthodes d’une interface dont vos classes héritent.

L’implémentation du pattern “Adapter” est une des solutions possibles permettant de répondre à ces problématiques.