Menu
Coddy logo textTech

Patrón Adapter

Parte de la sección Programación Orientada a Objetos del Journey de C# de Coddy — lección 57 de 70.

El patrón Adapter es un patrón 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 los clientes esperan. Piense en ello como un adaptador de corriente que le permite enchufar un dispositivo europeo en un toma de corriente americano.

Este patrón es particularmente útil cuando quieres usar una clase existente pero su interfaz no coincide con lo que tu código necesita. En lugar de modificar la clase original (la cual podrías no controlar), creas un adaptador que la envuelve:

// Clase existente con interfaz incompatible
public class OldPrinter
{
    public void PrintMessage(string msg) => Console.WriteLine($"Old: {msg}");
}

// Interfaz que su código espera
public interface IPrinter
{
    void Print(string text);
}

// El adaptador cierra la brecha
public class PrinterAdapter : IPrinter
{
    private OldPrinter _oldPrinter;
    
    public PrinterAdapter(OldPrinter oldPrinter)
    {
        _oldPrinter = oldPrinter;
    }
    
    public void Print(string text)
    {
        _oldPrinter.PrintMessage(text);  // Delega a la interfaz antigua
    }
}

Ahora su código puede funcionar con la impresora antigua a través de la interfaz esperada:

OldPrinter legacy = new OldPrinter();
IPrinter printer = new PrinterAdapter(legacy);

printer.Print("Hello");  // Anterior: Hello

El patrón Adapter es invaluable al integrar librerías de terceros o código legado en tu aplicación. El código del cliente trabaja con la interfaz IPrinter, sin saber en absoluto que una clase antigua e incompatible está realizando el trabajo real entre bastidores.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de reproductor de medios utilizando el patrón Adapter. Tienes una biblioteca de audio existente que reproduce archivos MP3, pero tu aplicación necesita una interfaz unificada que pueda manejar diferentes tipos de medios. Crearás un adaptador para cerrar esta brecha, permitiendo que tu reproductor de medios moderno funcione sin problemas con la biblioteca de audio heredada.

Organizarás tu código en tres archivos:

  • LegacyAudio.cs: Esto representa una biblioteca existente que no puedes modificar. Crea una clase LegacyAudioPlayer en el espacio de nombres MediaSystem con un método PlayMp3(string filename) que devuelva la cadena "Playing MP3: {filename}". Este es tu "adaptee": la clase con la interfaz incompatible.
  • MediaAdapter.cs: Crea la interfaz y el adaptador en el mismo espacio de nombres. Define una interfaz IMediaPlayer con un método Play(string filename) que devuelva una cadena. Luego, crea una clase MediaPlayerAdapter que implemente IMediaPlayer. Tu adaptador debe envolver una instancia de LegacyAudioPlayer (pasada a través del constructor) y traducir la llamada Play al método PlayMp3 del reproductor heredado.
  • Program.cs: Une todo creando el reproductor heredado, envolviéndolo en tu adaptador y utilizando el adaptador a través de la interfaz IMediaPlayer. Esto demuestra cómo el código del cliente puede trabajar con la interfaz moderna mientras el adaptador se encarga de la comunicación con el sistema heredado entre bastidores.

Recibirás una entrada:

  • El nombre del archivo a reproducir (por ejemplo, song.mp3)

Crea un LegacyAudioPlayer, envuélvelo en un MediaPlayerAdapter, luego llama a Play en el adaptador utilizando la interfaz IMediaPlayer e imprime el resultado.

Por ejemplo, si la entrada es favorite_track.mp3, la salida debería ser:

Playing MP3: favorite_track.mp3

La belleza de este patrón es que tu código principal solo interactúa con IMediaPlayer; no tiene idea de que una biblioteca de audio heredada está haciendo el trabajo real. Si más adelante necesitas dar soporte a una biblioteca heredada diferente, ¡simplemente crearías un nuevo adaptador sin cambiar nada del código del cliente!

Hoja de referencia

El patrón Adapter es un patrón estructural que permite que interfaces incompatibles trabajen juntas actuando como un puente entre dos clases.

El patrón convierte la interfaz de una clase en una interfaz que los clientes esperan, lo cual es útil cuando se desea utilizar una clase existente pero su interfaz no coincide con las necesidades de su código.

Estructura básica:

// Clase existente con interfaz incompatible (Adaptee)
public class OldPrinter
{
    public void PrintMessage(string msg) => Console.WriteLine($"Old: {msg}");
}

// Interfaz objetivo que su código espera
public interface IPrinter
{
    void Print(string text);
}

// El adaptador cierra la brecha
public class PrinterAdapter : IPrinter
{
    private OldPrinter _oldPrinter;
    
    public PrinterAdapter(OldPrinter oldPrinter)
    {
        _oldPrinter = oldPrinter;
    }
    
    public void Print(string text)
    {
        _oldPrinter.PrintMessage(text);  // Delega a la interfaz antigua
    }
}

Uso:

OldPrinter legacy = new OldPrinter();
IPrinter printer = new PrinterAdapter(legacy);

printer.Print("Hello");  // Old: Hello

El código del cliente trabaja con la interfaz objetivo, sin saber que una clase incompatible está realizando el trabajo real entre bastidores. Este patrón es particularmente valioso al integrar librerías de terceros o código heredado.

Pruébalo tú mismo

using System;
using MediaSystem;

class Program
{
    public static void Main(string[] args)
    {
        // Lee la entrada del nombre de archivo
        string filename = Console.ReadLine();
        
        // TODO: Crea una instancia de LegacyAudioPlayer
        
        // TODO: Envuélvelo en un MediaPlayerAdapter
        
        // TODO: Usa el adaptador a través de la interfaz IMediaPlayer
        // e imprime el resultado de llamar a Play con el nombre de archivo
    }
}
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