Introducción
El patrón Adapter (Adaptador) es un patrón estructural que permite que dos interfaces incompatibles trabajen juntas. Este patrón actúa como un puente entre dos interfaces incompatibles al convertir la interfaz de una clase en otra interfaz que el cliente espera.
Objetivos del Patrón Adapter
- Permitir que clases con interfaces incompatibles trabajen juntas.
- Proporcionar una interfaz uniforme para una clase existente.
- Facilitar la reutilización de clases existentes sin modificar su código.
Conceptos Clave
Participantes del Patrón Adapter
- Cliente (Client): La clase que utiliza la interfaz del adaptador.
- Target: La interfaz esperada por el cliente.
- Adaptee: La clase que tiene una interfaz incompatible con la del cliente.
- Adapter: La clase que implementa la interfaz Target y traduce las llamadas del cliente a la interfaz del Adaptee.
Diagrama UML del Patrón Adapter
+-------------+ +-------------+ +-------------+ | Client | | Adapter | | Adaptee | +-------------+ +-------------+ +-------------+ | - target |----->| - adaptee |----->| - specific | | | | | | methods | +-------------+ +-------------+ +-------------+
Ejemplo Práctico
Escenario
Supongamos que tenemos una aplicación que procesa pagos. La aplicación utiliza una interfaz PaymentProcessor
para procesar pagos, pero ahora necesitamos integrar un nuevo sistema de pagos que tiene una interfaz diferente.
Código
Interfaz Target (PaymentProcessor)
Clase Adaptee (NewPaymentSystem)
public class NewPaymentSystem { public void makePayment(double amount) { System.out.println("Payment of $" + amount + " made using NewPaymentSystem."); } }
Clase Adapter (PaymentAdapter)
public class PaymentAdapter implements PaymentProcessor { private NewPaymentSystem newPaymentSystem; public PaymentAdapter(NewPaymentSystem newPaymentSystem) { this.newPaymentSystem = newPaymentSystem; } @Override public void processPayment(double amount) { newPaymentSystem.makePayment(amount); } }
Clase Cliente (Client)
public class Client { public static void main(String[] args) { NewPaymentSystem newPaymentSystem = new NewPaymentSystem(); PaymentProcessor paymentProcessor = new PaymentAdapter(newPaymentSystem); paymentProcessor.processPayment(100.0); } }
Explicación del Código
- Interfaz Target (PaymentProcessor): Define el método
processPayment
que el cliente espera. - Clase Adaptee (NewPaymentSystem): Tiene un método
makePayment
que es incompatible con la interfazPaymentProcessor
. - Clase Adapter (PaymentAdapter): Implementa la interfaz
PaymentProcessor
y traduce las llamadas al métodomakePayment
deNewPaymentSystem
. - Clase Cliente (Client): Utiliza la interfaz
PaymentProcessor
para procesar pagos. El adaptador permite que el cliente utiliceNewPaymentSystem
sin cambios en el código del cliente.
Ejercicio Práctico
Ejercicio
Supongamos que tienes una aplicación que necesita mostrar mensajes en diferentes formatos. Tienes una clase OldMessageSystem
que muestra mensajes en formato de texto simple, pero ahora necesitas integrar una nueva clase NewMessageSystem
que muestra mensajes en formato JSON.
- Define la interfaz
MessageDisplay
con un métododisplayMessage(String message)
. - Implementa la clase
OldMessageSystem
con un métodoshowMessage(String message)
. - Implementa la clase
NewMessageSystem
con un métododisplayJsonMessage(String message)
. - Crea una clase
MessageAdapter
que implemente la interfazMessageDisplay
y traduzca las llamadas al métododisplayJsonMessage
deNewMessageSystem
. - Escribe una clase
Client
que utilice la interfazMessageDisplay
para mostrar mensajes.
Solución
Interfaz Target (MessageDisplay)
Clase Adaptee (OldMessageSystem)
public class OldMessageSystem { public void showMessage(String message) { System.out.println("Old Message: " + message); } }
Clase Adaptee (NewMessageSystem)
public class NewMessageSystem { public void displayJsonMessage(String message) { System.out.println("{ \"message\": \"" + message + "\" }"); } }
Clase Adapter (MessageAdapter)
public class MessageAdapter implements MessageDisplay { private NewMessageSystem newMessageSystem; public MessageAdapter(NewMessageSystem newMessageSystem) { this.newMessageSystem = newMessageSystem; } @Override public void displayMessage(String message) { newMessageSystem.displayJsonMessage(message); } }
Clase Cliente (Client)
public class Client { public static void main(String[] args) { NewMessageSystem newMessageSystem = new NewMessageSystem(); MessageDisplay messageDisplay = new MessageAdapter(newMessageSystem); messageDisplay.displayMessage("Hello, World!"); } }
Explicación del Ejercicio
- Interfaz Target (MessageDisplay): Define el método
displayMessage
que el cliente espera. - Clase Adaptee (OldMessageSystem): Tiene un método
showMessage
que muestra mensajes en formato de texto simple. - Clase Adaptee (NewMessageSystem): Tiene un método
displayJsonMessage
que muestra mensajes en formato JSON. - Clase Adapter (MessageAdapter): Implementa la interfaz
MessageDisplay
y traduce las llamadas al métododisplayJsonMessage
deNewMessageSystem
. - Clase Cliente (Client): Utiliza la interfaz
MessageDisplay
para mostrar mensajes. El adaptador permite que el cliente utiliceNewMessageSystem
sin cambios en el código del cliente.
Conclusión
El patrón Adapter es una herramienta poderosa para integrar clases con interfaces incompatibles en un sistema. Al utilizar un adaptador, puedes reutilizar código existente sin modificarlo, lo que facilita la integración de nuevas funcionalidades y mejora la mantenibilidad del sistema.
En el próximo tema, exploraremos el patrón Bridge, que también es un patrón estructural pero con un enfoque diferente para separar una abstracción de su implementación.
Curso de Patrones de Diseño de Software
Módulo 1: Introducción a los Patrones de Diseño
- ¿Qué son los Patrones de Diseño?
- Historia y Origen de los Patrones de Diseño
- Clasificación de los Patrones de Diseño
- Ventajas y Desventajas de Usar Patrones de Diseño
Módulo 2: Patrones Creacionales
- Introducción a los Patrones Creacionales
- Singleton
- Factory Method
- Abstract Factory
- Builder
- Prototype
Módulo 3: Patrones Estructurales
Módulo 4: Patrones de Comportamiento
- Introducción a los Patrones de Comportamiento
- Chain of Responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Observer
- State
- Strategy
- Template Method
- Visitor
Módulo 5: Aplicación de Patrones de Diseño
- Cómo Seleccionar el Patrón Adecuado
- Ejemplos Prácticos de Uso de Patrones
- Patrones de Diseño en Proyectos Reales
- Refactorización Usando Patrones de Diseño
Módulo 6: Patrones de Diseño Avanzados
- Patrones de Diseño en Arquitecturas Modernas
- Patrones de Diseño en Microservicios
- Patrones de Diseño en Sistemas Distribuidos
- Patrones de Diseño en Desarrollo Ágil