Patrones estructurales: Adapter, Decorator y Facade
Componga objetos y simplifique interfaces mediante patrones estructurales.
Patrones estructurales: Adapter, Decorator y Facade es una lección gratuita de PHP Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de PHP Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de PHP Academy incluye 4 lecciones en total.
Componer objetos
Los patrones estructurales describen cómo componer clases y objetos en estructuras mayores manteniéndolos flexibles. Cubrimos tres patrones esenciales:
- Adapter — hace utilizable una interfaz incompatible.
- Decorator — añade comportamiento sin crear subclases.
- Facade — presenta una interfaz sencilla ante un subsistema complejo.
Adapter: el problema
Depende de una interfaz PaymentGateway, pero un SDK de terceros expone chargeCard($amountInCents) con una forma diferente. Llamar directamente al SDK filtra su API por todo el código. A continuación, las dos interfaces son claramente incompatibles; esa discrepancia es exactamente lo que resuelve un adaptador.
<?php
// What our app wants to depend on
interface PaymentGateway { public function pay(float $dollars): string; }
// What the vendor actually gives us (cents, array result)
final class StripeSdk {
public function chargeCard(int $cents): array {
return ['id' => 'ch_1', 'amount' => $cents];
}
}
// dollars vs cents, string vs array -> shapes don't line up
var_dump((new StripeSdk())->chargeCard(2000));
Adapter en código
El adaptador mantiene el objeto adaptado e implementa su interfaz objetivo, convirtiendo los argumentos y los valores devueltos. El código de la aplicación se mantiene limpio e independiente del proveedor.
<?php
interface PaymentGateway { public function pay(float $dollars): string; }
// Third-party SDK with an incompatible API
final class StripeSdk {
public function chargeCard(int $cents): array {
return ['id' => 'ch_1', 'amount' => $cents];
}
}
final class StripeAdapter implements PaymentGateway {
public function __construct(private StripeSdk $sdk) {}
public function pay(float $dollars): string {
$res = $this->sdk->chargeCard((int) round($dollars * 100));
return "charged {$res['amount']}c -> {$res['id']}";
}
}
echo (new StripeAdapter(new StripeSdk()))->pay(20.0), PHP_EOL;
Decorator: la idea
Un Decorator envuelve un objeto que comparte su interfaz y añade comportamiento antes o después de delegar. A diferencia de la herencia, los decoradores se apilan en tiempo de ejecución, lo que permite combinar funcionalidades en cualquier orden sin que el número de clases se dispare. Este es el esqueleto mínimo: un envoltorio que implementa la misma interfaz y contiene la instancia interna.
<?php
interface Coffee { public function cost(): float; }
final class Espresso implements Coffee {
public function cost(): float { return 2.0; }
}
final class WithMilk implements Coffee {
public function __construct(private Coffee $inner) {}
public function cost(): float { return $this->inner->cost() + 0.5; }
}
echo (new WithMilk(new Espresso()))->cost(), PHP_EOL; // 2.5
Decorator en código
Cada decorador implementa la misma interfaz y contiene una instancia interna. Aquí envolvemos una fuente de datos con almacenamiento en caché y registro, y los componemos libremente.
<?php
interface DataSource { public function read(): string; }
final class FileSource implements DataSource {
public function read(): string { return 'raw-data'; }
}
final class UpperCaseDecorator implements DataSource {
public function __construct(private DataSource $inner) {}
public function read(): string { return strtoupper($this->inner->read()); }
}
final class ExclaimDecorator implements DataSource {
public function __construct(private DataSource $inner) {}
public function read(): string { return $this->inner->read() . '!!!'; }
}
$src = new ExclaimDecorator(new UpperCaseDecorator(new FileSource()));
echo $src->read(), PHP_EOL; // RAW-DATA!!!
Decoradores en la práctica
El middleware de PSR-7 / PSR-15 es, en esencia, el patrón Decorator aplicado al tratamiento HTTP: cada middleware envuelve al siguiente y añade autenticación, registro o almacenamiento en caché alrededor de la solicitud y la respuesta. Los envoltorios de streams y las capas de caché PSR-6/16 también utilizan habitualmente la decoración. La característica clave es que el envoltorio puede sustituir al objeto que envuelve.
Decorator frente a herencia
La herencia fija el comportamiento en tiempo de compilación y solo permite una clase base. La decoración es dinámica y composable. Elija decoradores cuando:
- se multipliquen las combinaciones de funcionalidades opcionales,
- deba añadirse o eliminarse comportamiento durante la ejecución,
- deba ampliar una clase
finalo de terceros de la que no pueda crear subclases.
Facade: la idea
Una Facade proporciona un único punto de entrada simplificado a un subsistema complejo compuesto por muchas clases. No oculta el subsistema (aún puede acceder a él), pero ofrece una API cómoda de alto nivel para el caso habitual. Compare la interacción detallada con el subsistema que aparece a continuación con la llamada de una sola línea a la fachada de la siguiente escena.
<?php
// Without a facade, the client wires every step itself
final class Cpu { public function boot(): string { return 'cpu '; } }
final class Disk { public function load(): string { return 'disk '; } }
final class Ram { public function check(): string { return 'ram'; } }
$out = (new Cpu())->boot() . (new Disk())->load() . (new Ram())->check();
echo $out, PHP_EOL; // cpu disk ram
Facade en código
La fachada coordina varios colaboradores detrás de un único método. Los clientes llaman a place() en lugar de conectar por sí mismos el inventario, el pago y el envío.
<?php
final class Inventory { public function reserve(string $sku): bool { return true; } }
final class Payments { public function charge(float $amt): bool { return true; } }
final class Shipping { public function dispatch(string $sku): string { return 'tracking-99'; } }
final class OrderFacade {
public function __construct(
private Inventory $inv,
private Payments $pay,
private Shipping $ship
) {}
public function place(string $sku, float $amount): string {
if (!$this->inv->reserve($sku)) { return 'out of stock'; }
if (!$this->pay->charge($amount)) { return 'payment failed'; }
return 'shipped: ' . $this->ship->dispatch($sku);
}
}
echo (new OrderFacade(new Inventory(), new Payments(), new Shipping()))
->place('ABC', 49.99), PHP_EOL;
Distinguir los tres patrones
- Adapter cambia una interfaz para que dos partes existentes puedan comunicarse; el comportamiento es el mismo, pero la forma es diferente.
- Decorator conserva la interfaz, pero añade comportamiento que puede apilarse durante la ejecución.
- Facade introduce una interfaz nueva y más sencilla delante de muchas clases.
Una prueba útil: Adapter trata de la compatibilidad, Decorator de la mejora y Facade de la simplificación.
Nota sobre las facades de Laravel
Las «facades» de Laravel son un mecanismo de proxy estático respaldado por el contenedor de servicios, no el patrón Facade de GoF. Comparten el objetivo de ofrecer una interfaz cómoda, pero difieren en su implementación. No confunda la terminología del framework con el patrón estructural al razonar sobre diseño.
Comprobación rápida
Identifique el patrón a partir de su intención.
Resumen
Ha compuesto objetos mediante tres patrones estructurales: Adapter para conectar interfaces incompatibles (p. ej., las de un SDK de un proveedor), Decorator para apilar comportamiento durante la ejecución (la base del middleware PSR-15) y Facade para ofrecer una interfaz sencilla ante un subsistema complejo. Cada uno reduce el acoplamiento, de modo que el código resiste mejor la dependencia de un proveedor y el exceso de funcionalidades.
Preguntas frecuentes
¿La lección «Patrones estructurales: Adapter, Decorator y Facade» es gratis?
Sí — el texto completo de «Patrones estructurales: Adapter, Decorator y Facade» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de PHP Academy, actualiza a CoddyKit PRO. El curso de PHP Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Patrones estructurales: Adapter, Decorator y Facade»?
Componga objetos y simplifique interfaces mediante patrones estructurales. Practicas PHP Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar PHP Academy?
No se requiere experiencia previa. PHP Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.
¿Cuánto tiempo toma la lección «Patrones estructurales: Adapter, Decorator y Facade»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de PHP Academy?
Sí. Cada lección de PHP Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Principios SOLID en la práctica
- Patrones creacionales: Factory, Builder y Singleton
- Patrones estructurales: Adapter, Decorator y Facade
- Patrones de comportamiento: Strategy, Observer y Command