Il Design Pattern Adapter in PHP: rendere compatibili classi e API diverse

by theArchitect
SHARE
Il Design Pattern Adapter in PHP: rendere compatibili classi e API diverse
© Guida-HTML5.it

Introduzione

Nel lavoro quotidiano con PHP capita spesso di dover integrare librerie esterne, servizi API o classi legacy che non seguono la stessa interfaccia del nostro codice. In questi casi, invece di modificare tutto il sistema o scrivere logica di conversione sparsa ovunque, il Design Pattern Adapter ci permette di creare un ponte tra due componenti incompatibili.

In pratica, l’Adapter “adatta” una classe esistente a un’interfaccia attesa dal nostro codice. È un pattern molto utile quando vogliamo:

  • integrare librerie di terze parti senza riscriverle;
  • riutilizzare codice legacy con interfacce diverse;
  • separare la logica di adattamento dal resto dell’applicazione;
  • mantenere il codice più pulito, testabile e facile da sostituire.

Un esempio reale: il tuo sistema invia notifiche con un metodo send(), ma un provider esterno espone un metodo deliverMessage() con parametri diversi. L’Adapter risolve questa differenza senza costringerti a cambiare tutto il codice che già usa send().

Codice completo

<?php

declare(strict_types=1);

/**
 * Interfaccia attesa dall´applicazione.
 * Tutto il codice interno lavorerà con questa forma standard.
 */
interface NotificationSender
{
    public function send(string $recipient, string $message): void;
}

/**
 * Classe legacy o libreria esterna che NON possiamo modificare.
 * Ha un´interfaccia diversa da quella che ci serve.
 */
class LegacySmsService
{
    public function deliverMessage(string $phoneNumber, string $text): bool
    {
        echo "SMS inviato a {$phoneNumber}: {$text}" . PHP_EOL;
        return true;
    }
}

/**
 * Adapter: rende compatibile LegacySmsService con NotificationSender.
 */
class SmsAdapter implements NotificationSender
{
    public function __construct(
        private LegacySmsService $legacySmsService
    ) {
    }

    public function send(string $recipient, string $message): void
    {
        // Adattamento dei nomi e del formato dei dati
        $this-

Spiegazione

Il codice mostra un caso molto comune: un servizio applicativo vuole inviare notifiche, ma i sistemi esterni hanno API diverse. Senza Adapter, il codice rischierebbe di essere pieno di if, conversioni manuali e dipendenze dirette verso classi esterne.

1. L’interfaccia comune

L’interfaccia NotificationSender rappresenta il contratto che il resto dell’applicazione si aspetta. È il punto di stabilità del sistema: qualsiasi classe che la implementa può essere usata da NotificationService.

2. La classe incompatibile

LegacySmsService e EmailApiClient simulano componenti esterni o vecchie classi già esistenti. Notiamo che i metodi non coincidono con l’interfaccia richiesta:

  • deliverMessage() invece di send();
  • un parametro singolo per SMS contro un array payload per email.

3. L’Adapter

SmsAdapter e EmailAdapter implementano l’interfaccia attesa dall’applicazione e traducono le chiamate nel formato corretto per il servizio reale. Questo è il cuore del pattern: convertire senza modificare il client.

Il vantaggio è importante: se domani cambiamo provider SMS o email, possiamo sostituire l’Adapter o crearne uno nuovo senza toccare NotificationService.

4. Il client applicativo

NotificationService non conosce i dettagli dei servizi esterni. Lavora solo con NotificationSender. Questo riduce l’accoppiamento e rende il codice più facile da testare, perché possiamo sostituire il sender con una finta implementazione nei test automatici.

Best practice

  • Definisci un’interfaccia chiara: l’Adapter funziona meglio quando il tuo codice interno si appoggia a un contratto semplice e stabile.
  • Limita la logica di conversione all’Adapter: evita di spargere trasformazioni di dati in più punti del progetto.
  • Non usare l’Adapter come “contenitore di tutto”: dovrebbe tradurre interfacce, non diventare una classe con troppa responsabilità.
  • Separa bene dominio e infrastruttura: il codice applicativo dovrebbe dipendere da astrazioni, non da dettagli esterni.
  • Usa type hint e strict_types: in PHP moderno aiuta a intercettare errori prima e rende il contratto più leggibile.
  • Scrivi test sull’interfaccia pubblica: testa NotificationService e gli Adapter, così puoi cambiare implementazione senza rompere il comportamento atteso.

Un errore comune è confondere Adapter con Facade. La Facade semplifica un sistema complesso offrendo un’interfaccia più comoda; l’Adapter invece rende compatibili due interfacce incompatibili. Nel dubbio, chiediti: sto semplificando o sto traducendo?

Riepilogo

Il Design Pattern Adapter è una soluzione elegante quando devi collegare componenti con interfacce diverse. In PHP è particolarmente utile con librerie esterne, servizi API e codice legacy. Grazie all’Adapter puoi:

  • mantenere un’interfaccia interna coerente;
  • isolare le differenze tra sistemi esterni;
  • ridurre l’accoppiamento;
  • facilitare test e manutenzione.

Se il tuo progetto cresce e integra sempre più servizi, l’Adapter diventa uno strumento fondamentale per evitare che l’incompatibilità tra API si trasformi in caos architetturale.

Approfondisci con risorse ufficiali

SHARE