Menu
Coddy logo textTech

Patrón Adapter

Parte de la sección Programación Orientada a Objetos del Journey de PHP de Coddy — lección 76 de 91.

El Patrón Adapter es un patrón de diseño estructural que permite que objetos con interfaces incompatibles trabajen juntos. Actúa como un puente entre dos interfaces, traduciendo las llamadas de un formato a otro.

Imagina que estás construyendo una aplicación que procesa pagos y necesitas integrar una biblioteca de pagos de terceros. La biblioteca funciona perfectamente, pero su interfaz no coincide con lo que tu código espera. En lugar de reescribir toda tu aplicación, creas un adaptador que traduce entre ambos.

<?php
// La interfaz que su aplicación espera
interface PaymentProcessor {
    public function pay(float $amount): string;
}

// Biblioteca de terceros con una interfaz diferente
class StripeAPI {
    public function createCharge(int $cents, string $currency): string {
        return "Charged {$cents} {$currency} via Stripe";
    }
}

El adaptador implementa la interfaz esperada mientras utiliza internamente la clase de terceros:

<?php
class StripeAdapter implements PaymentProcessor {
    public function __construct(private StripeAPI $stripe) {}
    
    public function pay(float $amount): string {
        $cents = (int)($amount * 100);
        return $this->stripe->createCharge($cents, 'USD');
    }
}

$stripe = new StripeAPI();
$processor = new StripeAdapter($stripe);
echo $processor->pay(29.99);

Resultado:

Charged 2999 USD via Stripe

El adaptador convierte dólares a centavos y llama al método apropiado. El código de su aplicación solo conoce PaymentProcessor, permaneciendo felizmente ajeno a los requisitos específicos de Stripe. Si más adelante cambia a un proveedor de pagos diferente, simplemente crea un nuevo adaptador sin cambiar su código existente.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de conversión de temperatura utilizando el Patrón Adapter. Tienes un sensor de temperatura heredado (legacy) que proporciona lecturas en Fahrenheit, pero tu aplicación meteorológica moderna espera todas las temperaturas en Celsius. En lugar de modificar cualquiera de los sistemas, crearás un adaptador que cierre la brecha.

Organizarás tu código en cuatro archivos:

  • TemperatureSensor.php — Define una interfaz TemperatureSensor que es la que espera tu aplicación meteorológica. Debe tener un método getTemperature(): float que devuelva la temperatura en Celsius.
  • LegacySensor.php — Crea una clase LegacySensor que simule el hardware antiguo. Esta clase tiene una interfaz diferente a la que necesita tu aplicación:
    • Recibe una lectura en Fahrenheit en su constructor (utiliza la promoción de propiedades del constructor)
    • Tiene un método readFahrenheit(): float que devuelve el valor Fahrenheit almacenado
  • LegacySensorAdapter.php — Incluye tanto la interfaz TemperatureSensor como la clase LegacySensor. Crea una clase LegacySensorAdapter que implemente TemperatureSensor y envuelva un LegacySensor. Tu adaptador debe:
    • Aceptar un LegacySensor en su constructor
    • Implementar getTemperature() leyendo el valor Fahrenheit del sensor heredado y convirtiéndolo a Celsius usando la fórmula: (fahrenheit - 32) * 5 / 9
  • main.php — Incluye el archivo LegacySensorAdapter. Recibirás una entrada: una temperatura en Fahrenheit.

    Crea un LegacySensor con la temperatura de entrada, luego envuélvelo en un LegacySensorAdapter. Llama a getTemperature() en el adaptador e imprime el resultado redondeado a dos decimales.

    El formato de salida debe ser: "Temperature: " . round($celsius, 2) . "C"

Este desafío demuestra cómo el Patrón Adapter te permite integrar interfaces incompatibles sin modificar el código existente. Tu aplicación meteorológica funciona exclusivamente con la interfaz TemperatureSensor, sin saber en absoluto que las lecturas reales provienen de un sensor Fahrenheit heredado.

Hoja de referencia

El Patrón Adapter es un patrón de diseño estructural que permite que objetos con interfaces incompatibles trabajen juntos actuando como un puente entre ellos.

Estructura Básica

Define la interfaz que espera tu aplicación:

<?php
interface PaymentProcessor {
    public function pay(float $amount): string;
}

Una clase de terceros con una interfaz diferente:

<?php
class StripeAPI {
    public function createCharge(int $cents, string $currency): string {
        return "Charged {$cents} {$currency} via Stripe";
    }
}

Creando el Adaptador

El adaptador implementa la interfaz esperada mientras utiliza internamente la clase de terceros:

<?php
class StripeAdapter implements PaymentProcessor {
    public function __construct(private StripeAPI $stripe) {}
    
    public function pay(float $amount): string {
        $cents = (int)($amount * 100);
        return $this->stripe->createCharge($cents, 'USD');
    }
}

Uso

$stripe = new StripeAPI();
$processor = new StripeAdapter($stripe);
echo $processor->pay(29.99);
// Salida: Charged 2999 USD via Stripe

El adaptador traduce entre interfaces, permitiendo que el código de tu aplicación permanezca sin cambios al integrar librerías de terceros o cambiar implementaciones.

Pruébalo tú mismo

<?php
require_once 'LegacySensorAdapter.php';

// Leer entrada
$fahrenheit = floatval(trim(fgets(STDIN)));

// TODO: Crear un LegacySensor con la temperatura de entrada
// TODO: Envolverlo en un LegacySensorAdapter
// TODO: Llamar a getTemperature() en el adaptador
// TODO: Imprimir el resultado redondeado a dos decimales
// Formato de salida: Temperature: [celsius]C

?>
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos