Adapter Pattern
- Type : Structurel
- Difficulté : 5/10
- Définition succincte : Le Adapter Pattern est un design pattern structurel qui permet de faire fonctionner ensemble des interfaces incompatibles en les adaptant l'une à l'autre. L'adaptateur agit comme un intermédiaire entre deux systèmes ou classes qui ne peuvent pas interagir directement. Cela permet de rendre un objet utilisable dans un contexte où son interface n'est pas compatible avec celle attendue.
- Contexte spécifique à Laravel : En Laravel, le Adapter Pattern est largement utilisé dans des services comme le mail, le cache, ou la queue. Laravel fournit des adaptateurs pour interagir avec des services tiers tout en exposant une API unifiée. Par exemple, le Mail Adapter permet d'utiliser différents services de messagerie (SMTP, Mailgun, etc.) via la même interface.
Objectif du Adapter Pattern
L'objectif du Adapter Pattern est de connecter des interfaces incompatibles sans modifier leur code d'origine. Cela permet de rendre des systèmes ou des classes déjà existants utilisables dans de nouveaux contextes, en transformant leur interface pour qu'elle soit compatible avec l'interface attendue par le client.
1. Exemple d'utilisation dans Laravel
En Laravel, les Adapters sont utilisés dans des services comme le mail ou le cache. Par exemple, pour l'envoi d'e-mails, Laravel utilise un adaptateur pour faire abstraction du service d'envoi (Mailgun, SMTP, etc.). Cela permet d'interagir avec ces services via une interface unique, sans avoir à gérer les différences de chaque service.
Voici un exemple d'utilisation de l'Adapter Pattern pour envoyer des e-mails en utilisant Laravel :
use Illuminate\Support\Facades\Mail;
// Envoyer un e-mail via l'adaptateur de Laravel
Mail::to('user@example.com')->send(new WelcomeMail());
Laravel utilise des adaptateurs pour envoyer des e-mails via des services comme Mailgun, SMTP, ou SES, tout en exposant une interface unifiée via la façade Mail.
2. Implémentation complète dans Laravel
Prenons un exemple dans un contexte différent. Supposons que tu reçois des données au format XML d'une librairie entrante, et que tu dois les convertir en JSON pour les envoyer à une librairie sortante. Le Adapter Pattern est idéal pour cette situation, car il te permet de convertir ces formats sans changer les bibliothèques d'origine.
Nous allons créer un adaptateur qui va :
- Recevoir des données en XML (depuis la librairie entrante).
- Convertir les données XML en JSON (format que la librairie sortante peut traiter).
a) Exemple de données XML et JSON
Données XML reçues (depuis la librairie entrante) :
<user>
<name>John Doe</name>
<email>john@example.com</email>
</user>
Données JSON attendues (par la librairie sortante) :
{
"name": "John Doe",
"email": "john@example.com"
}
b) Implémentation de l'adaptateur
Nous allons implémenter l'Adapter Pattern pour convertir le format XML en JSON.
Interface LibraryAdapterInterface
Tout d'abord, définissons une interface pour notre adaptateur. Cela te permet d'étendre ou d'ajouter d'autres adaptateurs à l'avenir.
// app/Services/Adapters/LibraryAdapterInterface.php
namespace App\Services\Adapters;
interface LibraryAdapterInterface
{
public function getData(): array;
}
Librairie entrante (renvoie du XML)
Simulons une librairie qui renvoie des données au format XML. Cela pourrait représenter un appel à une API ou un traitement de données internes.
// app/Services/Adapters/IncomingXmlLibrary.php
namespace App\Services\Adapters;
class IncomingXmlLibrary
{
public function getXmlData(): string
{
// Données XML simulées
return <<<XML
<user>
<name>John Doe</name>
<email>john@example.com</email>
</user>
XML;
}
}
Librairie sortante (attend du JSON)
Simulons une librairie sortante qui attend du JSON en tant qu'entrée.
// app/Services/Adapters/OutgoingJsonLibrary.php
namespace App\Services\Adapters;
class OutgoingJsonLibrary
{
public function sendJsonData(array $data)
{
// Simule l'envoi de données JSON
return "Sending data: " . json_encode($data);
}
}
Création de l'adaptateur XML -> JSON
L'adaptateur va :
- Appeler la méthode de la librairie entrante pour obtenir les données XML.
- Convertir les données XML en tableau associatif.
- Retourner les données prêtes à être envoyées sous forme de JSON.
// app/Services/Adapters/XmlToJsonAdapter.php
namespace App\Services\Adapters;
class XmlToJsonAdapter implements LibraryAdapterInterface
{
protected $xmlLibrary;
public function __construct(IncomingXmlLibrary $xmlLibrary)
{
$this->xmlLibrary = $xmlLibrary;
}
public function getData(): array
{
// Obtenir les données XML depuis la librairie entrante
$xmlData = $this->xmlLibrary->getXmlData();
// Convertir XML en tableau associatif
$xmlObject = simplexml_load_string($xmlData);
$json = json_encode($xmlObject);
return json_decode($json, true);
}
}
c) Utilisation de l'adaptateur dans une commande CLI
Nous allons maintenant utiliser l'adaptateur dans une commande CLI pour simuler la conversion des données XML en JSON.
// app/Console/Commands/ProcessLibraryDataCommand.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Services\Adapters\IncomingXmlLibrary;
use App\Services\Adapters\OutgoingJsonLibrary;
use App\Services\Adapters\XmlToJsonAdapter;
class ProcessLibraryDataCommand extends Command
{
protected $signature = 'library:process-data';
protected $description = 'Process data from XML to JSON using Adapter Pattern';
public function handle()
{
// Instancier la librairie entrante qui retourne du XML
$incomingLibrary = new IncomingXmlLibrary();
// Créer l'adaptateur pour convertir XML en JSON
$adapter = new XmlToJsonAdapter($incomingLibrary);
// Récupérer les données converties en JSON (sous forme de tableau associatif)
$jsonData = $adapter->getData();
// Instancier la librairie sortante qui accepte du JSON
$outgoingLibrary = new OutgoingJsonLibrary();
// Envoyer les données JSON à la librairie sortante
$result = $outgoingLibrary->sendJsonData($jsonData);
$this->info($result);
}
}
d) Exécution de la commande
Tu peux maintenant exécuter la commande suivante pour traiter les données :
php artisan library:process-data
Exemple de sortie
Sending data: {"name":"John Doe","email":"john@example.com"}
Avantages du Adapter Pattern
- Réutilisabilité : Il permet de réutiliser des classes ou services existants dans de nouveaux contextes sans modifier leur code.
- Flexibilité : Le pattern permet de connecter des systèmes ou des interfaces incompatibles sans forcer les deux à être modifiés.
- Découplage : Le Adapter Pattern sépare les responsabilités en cachant les détails de l'implémentation d'un service ou d'une classe, rendant le code plus modulaire.
Inconvénients du Adapter Pattern
- Complexité accrue : Ajouter un adaptateur peut introduire une couche supplémentaire de complexité, en particulier si les systèmes à adapter sont déjà complexes.
- Difficulté de maintenance : Si les interfaces changent souvent, l'adaptateur doit être mis à jour régulièrement pour rester compatible avec les deux systèmes.
Conclusion
Le Adapter Pattern est un pattern extrêmement utile pour intégrer des systèmes ou des services existants dans une nouvelle architecture sans modifier leur code d'origine. En Laravel, ce pattern est fréquemment utilisé pour intégrer des services comme le mail ou le cache via des adaptateurs, rendant l'application plus flexible et modulaire. Le pattern te permet d'utiliser des interfaces incompatibles ensemble en introduisant une classe intermédiaire qui fait le lien entre elles.