Design Patterns - Adapter

Sabe quando seu sistema legado precisa de um feature nova mas a biblioteca que você usa não tem suporte para isso e a biblioteca que você achou para implementar não faz o que a biblioteca antiga faz e de alguma forma você precisa fazer as duas trabalharem juntas no seu sistema ?! É aí que podemos contar com o Design Patter Adapter!

Design Patter - Adapter é um padrão estrutural que permite objetos com interfaces incompatíveis trabalhem juntos!

Estrutura básica

  1. Target ( Alvo ) - é (geralmente) a nova interface que precisamos adicionar ao nosso projeto

  2. Adapter ( Adaptador ) - irá realizar ajustes necessários, convertendo a interface da classe a ser adaptada para que a interface target possa ser utilizada

  3. Adaptee ( Classe adaptada ) - nossa classe legada, a classe que faz todo esse esforço ser necessário

  4. Client - Usa a interface Target para interagir com os objetos do sistema

Situação problema

Vamos esmiuçar essa estrutura com um exemplo. Imagina que você faz parte da equipe do Spotify e a empresa decidiu que agora irão trabalhar com vídeos. O júnior da equipe logo fica ansioso imaginando que será necessário refazer todo o código, procurar uma nova biblioteca que suporte tanto áudios mp3 e os vídeos mp4. Ele chega a sugerir isso na reunião mas todo mundo fica preocupado com a ideia de mexer no que já está funcionando, mas e se houvesse uma forma de fazer uma biblioteca de vídeos funcionar junto com a biblioteca de áudio que a equipe já está acostumada a usar?!

É nesse momento que vamos propor nosso mais novo amigo como a solução dos problems!

Mão na massa!

Vamos iniciar criando nossa interface target, ela deverá ter a declaração de um método Play que recebe o nome do arquivo a ser executado.

Interface Alvo (Target)

public interface IMidiaPlayer
{
    void Play(string file);
}

Nossa classe antiga .mp3

Observe que ela só sabe executar .mp3

public class Mp3Player
{
    public void PlayMp3( string file)
    {
        Console.WriteLine($"Reproduzindo MP3: {file}");
    }
}

Nossa nova classe .mp4

Esta classe já implementa nossa interface mas ainda falta a estrela dessa operação

public class Mp4Player : IMidiaPlayer
{
    public void Play(string file)
    {
        Console.WriteLine($"Reproduzindo MP4: {file}");
    }
}

A estrela do dia: Mp3PlayerAdapter

Note como ela será responsável por tornar viável a integração entre as nossas classes mp3 e mp4

public class Mp3PlayerAdapter : IMidiaPlayer
{
    private readonly Mp3Player mp3Player;
    private readonly Mp4Player mp4Player;

    public Mp3PlayerAdapter(Mp3Player mp3Player_, Mp4Player mp4Player_)
    {
        mp3Player = mp3Player_;
        mp4Player = mp4Player_;
    }

    public void Play(string file)
    {
        if(file.EndsWith(".mp3"))
            mp3Player.PlayMp3(file);
        if(file.EndsWith(".mp4"))
            mp4Player.Play(file);
    }

}

Media Client

public class MediaClient
{
    private readonly IMidiaPlayer mediaPlayer;

    public MediaClient(IMidiaPlayer mediaPlayer_)
    {
        mediaPlayer = mediaPlayer_;
    }

    public void Play(string file)
    {
        mediaPlayer.Play(file);
    }
}

Main

namespace AdapterPlayer
{
    class Program
    {
        static void Main(string[] args)
        {
            var serviceProvider = new ServiceCollection()
                .AddScoped<Mp4Player>()
                .AddScoped<Mp3Player>() 
                .AddScoped<IMidiaPlayer, Mp3PlayerAdapter>() 
                .AddScoped<MediaClient>()
                .BuildServiceProvider();

            var mediaClient = serviceProvider.GetRequiredService<MediaClient>();  

            mediaClient.Play("musica.mp3");
            mediaClient.Play("video.mp4");
            mediaClient.Play("documento.pdf");
        }
    }
}

Resultado em tela

Olha que legal, o arquivo .pdf foi ignorado já que não possui uma classe que seja capaz de executá-lo.

Reproduzindo MP3: musica.mp3

Reproduzindo MP4: video.mp4

Algumas considerações sobre esse padrão

Esse padrão é um coringa muito interessante para se ter em mente, ele tem como vantagens a flexibilidade, o desacoplamento, a reutilização de código, facilita a integração de sistemas legados e ainda melhora a legibilidade do código! Mas como nem tudo são flores, é necessário certos cuidados, esse padrão pode aumentar a complexidade do seu sistema, limitar a capacidade de debugar o código... Como tudo na vida, use com moderação!

Repositório GIT

Design Patterns

Materiais de Estudo

Estamos chegando ao fim do nosso artigo e queria deixar alguns materiais que usei para estudar esse padrão de software:

Refactoring Guru

Dofactory

Padrões de Projetos: Soluções Reutilizáveis de Software Orientados a Objetos

Padrão Adapter - DevMedia

0
Subscribe to my newsletter

Read articles from Nicolas de Souza directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Nicolas de Souza
Nicolas de Souza