Menu
Coddy logo textTech

Patrón Adapter

Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy — lección 71 de 87.

El Patrón Adaptador es un patrón de diseño estructural que permite que interfaces incompatibles trabajen juntas. Actúa como un puente entre dos clases, convirtiendo la interfaz de una clase en una interfaz que el cliente espera. Piénselo como un adaptador de corriente que le permite enchufar un dispositivo europeo en un tomacorriente americano.

Imagina que tienes una interfaz MediaPlayer existente que reproduce archivos de audio, pero necesitas integrar una biblioteca de terceros que utiliza una interfaz completamente diferente para reproducir videos:

// Interfaz existente que utiliza su código
interface MediaPlayer {
    void play(String filename);
}

// Clase de terceros con una interfaz incompatible
class AdvancedVideoPlayer {
    public void playVideo(String filename) {
        System.out.println("Playing video: " + filename);
    }
}

El adaptador envuelve la clase incompatible e implementa la interfaz esperada, traduciendo las llamadas entre ellas:

class VideoPlayerAdapter implements MediaPlayer {
    private AdvancedVideoPlayer videoPlayer;
    
    public VideoPlayerAdapter() {
        this.videoPlayer = new AdvancedVideoPlayer();
    }
    
    public void play(String filename) {
        videoPlayer.playVideo(filename);
    }
}

Ahora el código de su cliente puede utilizar el reproductor de vídeo a través de la conocida interfaz MediaPlayer:

MediaPlayer player = new VideoPlayerAdapter();
player.play("movie.mp4");  // Salida: Reproduciendo video: movie.mp4

El patrón Adapter es inestimable al integrar código heredado o bibliotecas de terceros sin modificar su código fuente. El cliente permanece ajeno al hecho de que está trabajando con una clase adaptada; simplemente utiliza la interfaz que conoce.

challenge icon

Desafío

Fácil

¡Vamos a construir un sistema de conversión de temperatura utilizando el Patrón Adapter! Tienes una aplicación meteorológica existente que funciona con temperaturas en Celsius, pero necesitas integrar un sensor de temperatura antiguo que solo ofrece lecturas en Fahrenheit. En lugar de modificar cualquiera de los dos sistemas, crearás un adaptador que cierre esa brecha.

Organizarás tu código en cuatro archivos:

  • TemperatureProvider.java: Define la interfaz que espera tu aplicación meteorológica. Debe declarar un método getTemperatureCelsius() que devuelva un double representando la temperatura en Celsius.
  • FahrenheitSensor.java: Esto representa el sensor antiguo con una interfaz incompatible. Crea una clase con un campo privado de tipo double para la temperatura en Fahrenheit, establecido a través del constructor. Debe tener un método readFahrenheit() que devuelva el valor Fahrenheit almacenado.
  • SensorAdapter.java: Crea el adaptador que hace que el sensor Fahrenheit sea compatible con tu aplicación meteorológica. Tu adaptador debe implementar TemperatureProvider y envolver un FahrenheitSensor. Cuando se llame a getTemperatureCelsius(), debe leer del sensor y convertir el valor a Celsius usando la fórmula: (fahrenheit - 32) * 5 / 9.
  • Main.java: ¡Une todo! Recibirás una entrada: una lectura de temperatura en Fahrenheit (double).

    Crea un FahrenheitSensor con el valor de entrada. Luego crea un SensorAdapter que envuelva este sensor. Almacena el adaptador en una variable de tipo TemperatureProvider para demostrar que tu aplicación meteorológica puede usarlo a través de la interfaz esperada.

    Imprime el resultado en este formato: "Temperature: " + String.format("%.1f", celsius) + " C" donde celsius está formateado con un decimal.

Recibirás una entrada: la temperatura en Fahrenheit (double).

Por ejemplo, con la entrada 98.6, tu salida sería:

Temperature: 37.0 C

Observa cómo tu clase Main trabaja completamente con la interfaz TemperatureProvider; no tiene idea de que la temperatura real proviene de un sensor Fahrenheit que está siendo adaptado entre bastidores. ¡Esta es la elegancia del Patrón Adapter!

Hoja de referencia

El Adapter Pattern (Patrón Adaptador) es un patrón de diseño estructural que permite que interfaces incompatibles trabajen juntas actuando como un puente entre dos clases, convirtiendo una interfaz en otra que el cliente espera.

Componentes Clave

  • Target Interface (Interfaz Objetivo): La interfaz que el cliente espera utilizar
  • Adaptee (Adaptado): La clase existente con una interfaz incompatible
  • Adapter (Adaptador): La clase que implementa la interfaz objetivo y envuelve al adaptado, traduciendo las llamadas entre ellos

Estructura Básica

// Target interface
interface MediaPlayer {
    void play(String filename);
}

// Adaptee (incompatible class)
class AdvancedVideoPlayer {
    public void playVideo(String filename) {
        System.out.println("Playing video: " + filename);
    }
}

// Adapter
class VideoPlayerAdapter implements MediaPlayer {
    private AdvancedVideoPlayer videoPlayer;
    
    public VideoPlayerAdapter() {
        this.videoPlayer = new AdvancedVideoPlayer();
    }
    
    public void play(String filename) {
        videoPlayer.playVideo(filename);
    }
}

// Client usage
MediaPlayer player = new VideoPlayerAdapter();
player.play("movie.mp4");  // Output: Playing video: movie.mp4

Cuándo Utilizarlo

El Adapter Pattern es útil cuando:

  • Se integra código heredado (legacy) o librerías de terceros sin modificar su código fuente
  • Se necesita hacer que interfaces incompatibles trabajen juntas
  • El cliente debe permanecer ajeno a la implementación adaptada

Pruébalo tú mismo

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        double fahrenheit = scanner.nextDouble();
        
        // TODO: Crea un FahrenheitSensor con el valor de entrada
        
        // TODO: Crea un SensorAdapter que envuelva el sensor
        
        // TODO: Almacena el adaptador en una variable TemperatureProvider
        
        // TODO: Obtén la temperatura en Celsius e imprímela
        // Formato: "Temperature: [celsius] C" con un decimal
        // Pista: Usa String.format("%.1f", value) para el formato
    }
}
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