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

  1. Cliente (Client): La clase que utiliza la interfaz del adaptador.
  2. Target: La interfaz esperada por el cliente.
  3. Adaptee: La clase que tiene una interfaz incompatible con la del cliente.
  4. 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)

public interface PaymentProcessor {
    void processPayment(double amount);
}

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

  1. Interfaz Target (PaymentProcessor): Define el método processPayment que el cliente espera.
  2. Clase Adaptee (NewPaymentSystem): Tiene un método makePayment que es incompatible con la interfaz PaymentProcessor.
  3. Clase Adapter (PaymentAdapter): Implementa la interfaz PaymentProcessor y traduce las llamadas al método makePayment de NewPaymentSystem.
  4. Clase Cliente (Client): Utiliza la interfaz PaymentProcessor para procesar pagos. El adaptador permite que el cliente utilice NewPaymentSystem 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.

  1. Define la interfaz MessageDisplay con un método displayMessage(String message).
  2. Implementa la clase OldMessageSystem con un método showMessage(String message).
  3. Implementa la clase NewMessageSystem con un método displayJsonMessage(String message).
  4. Crea una clase MessageAdapter que implemente la interfaz MessageDisplay y traduzca las llamadas al método displayJsonMessage de NewMessageSystem.
  5. Escribe una clase Client que utilice la interfaz MessageDisplay para mostrar mensajes.

Solución

Interfaz Target (MessageDisplay)

public interface MessageDisplay {
    void displayMessage(String message);
}

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

  1. Interfaz Target (MessageDisplay): Define el método displayMessage que el cliente espera.
  2. Clase Adaptee (OldMessageSystem): Tiene un método showMessage que muestra mensajes en formato de texto simple.
  3. Clase Adaptee (NewMessageSystem): Tiene un método displayJsonMessage que muestra mensajes en formato JSON.
  4. Clase Adapter (MessageAdapter): Implementa la interfaz MessageDisplay y traduce las llamadas al método displayJsonMessage de NewMessageSystem.
  5. Clase Cliente (Client): Utiliza la interfaz MessageDisplay para mostrar mensajes. El adaptador permite que el cliente utilice NewMessageSystem 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.

© Copyright 2024. Todos los derechos reservados