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
processPaymentque el cliente espera. - Clase Adaptee (NewPaymentSystem): Tiene un método
makePaymentque es incompatible con la interfazPaymentProcessor. - Clase Adapter (PaymentAdapter): Implementa la interfaz
PaymentProcessory traduce las llamadas al métodomakePaymentdeNewPaymentSystem. - Clase Cliente (Client): Utiliza la interfaz
PaymentProcessorpara procesar pagos. El adaptador permite que el cliente utiliceNewPaymentSystemsin 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
MessageDisplaycon un métododisplayMessage(String message). - Implementa la clase
OldMessageSystemcon un métodoshowMessage(String message). - Implementa la clase
NewMessageSystemcon un métododisplayJsonMessage(String message). - Crea una clase
MessageAdapterque implemente la interfazMessageDisplayy traduzca las llamadas al métododisplayJsonMessagedeNewMessageSystem. - Escribe una clase
Clientque utilice la interfazMessageDisplaypara 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
displayMessageque el cliente espera. - Clase Adaptee (OldMessageSystem): Tiene un método
showMessageque muestra mensajes en formato de texto simple. - Clase Adaptee (NewMessageSystem): Tiene un método
displayJsonMessageque muestra mensajes en formato JSON. - Clase Adapter (MessageAdapter): Implementa la interfaz
MessageDisplayy traduce las llamadas al métododisplayJsonMessagedeNewMessageSystem. - Clase Cliente (Client): Utiliza la interfaz
MessageDisplaypara mostrar mensajes. El adaptador permite que el cliente utiliceNewMessageSystemsin 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
