Le patron de conception "Adapter"

Introduction

Avec le multiplication des libraries et framework, un développeur est de plus en plus amené à utilisé deux classes issue de deux bibliothèque non prévu pour fonctionner ensemble. Le design pattern adapter est permet d'établir des ponts et d'adapter — comme son nom l'indique — un objet à un autre.

Il permet :

  • de palier un incompatibilité d'interface
  • de ne pas coupler fortement deux bibliothèques, ou de ne pas coupler votre code métier à une bibliothèque.
  • d'intégrer une classe à un code existant sans les modifiers

Comment ça marche ?

L'idée est de créer un objet Adapter implémentant l'interface à adapter — ou au moins répondant aux spécification attendu par la cible — et d'y encapsuler l'objet source. L'adapter se charge alors de convertir le données de l'objet source afin de répondre au contrat de l'objet cible.

Exemple

Vous avez développer une application qui envoie des mails. Vous avez votre modèle Mail qui contient les données du mail à envoyer et des données metier.

class Mail
{
    private $from;
    private $to;
    private $subject;
    private $message;

    // Getter and setter
}

Vous créez une interface décrivant un service d'envoie de mail :

interface MailerInterface
{
    public function send(Mail $mail);
}

Vous installer ensuite une bibliothèque d'envoie de mail comme par exemple SwiftMailer. Or le mailer SwiftMailer dispose d'une méthode send attendant une instance de Swift_Mime_Message en paramètre. Le mailer est incompatible avec votre interface et votre classe métier.

Il faut donc créer un adapteur qui se chargera de faire le pont entre les deux. L'adapteur doit répondre à votre interface et encapsuler le mailer de SwiftMailer afin d'adapter votre classe métier au attente de celui ci.

class SwiftMailerAdapter implement MailerInterface
{
    private $mailer;

    public function __construct(\Swift_Mailer $mailer)
    {
         $this->mailer = $mailer;
    }

    public function send(Mail $mail)
    {
         $message = \Swift_Message::newInstance($mail->getSubject(), $mail->getContent(), 'plain/text', 'UTF-8');
         $message->setFrom($mail->getFrom());
         $message->setTo($mail->setTo());

         $this->mailer->send($message);
    }
}

L'utilisation de SwiftMailer est ainsi transparente pour vous. Si vous devez changer de service d'envoie de mail, il vous suffira d'écrire un nouvel adapteur correspondant au nouveau service et le changement se fera sans autre impact sur le code de l'application.

Les commentaires