Design Pattern Adapter em C#

evertonandrade

Everton Andrade

Posted on October 4, 2020

Design Pattern Adapter em C#

O design pattern Adapter é um padrão de projeto do tipo estrutural que permite que interfaces incompatíveis funcionem juntas. Fazendo isso, permitimos que objetos de diferentes interfaces se comuniquem.

Neste artigo, vamos aprender como implementar o padrão Adapter em nosso projeto e quando devemos usá-lo.

Este artigo está dividido nas seguintes seções:

  • Projeto Inicial
  • Implementação do Adapter
  • Quando usar o Adapter
  • Conclusão

Projeto Inicial

Vamos imaginar que temos uma funcionalidade na qual convertemos uma lista de fabricantes de automóveis para o formato JSON e a escrevemos na tela. Mas, em vez de uma lista, foi fornecida uma API que nos fornece todos os fabricantes no formato XML.

Digamos que não possamos modificar a funcionalidade da API existente (por causa de restrições técnicas, como ser importado para o nosso projeto de outra solução que não devemos modificar ou como um pacote NuGet), então temos que encontrar uma maneira de contornar isso.

E a maneira correta de fazer isso é implementar o padrão Adapter para resolver esse problema.

Vamos começar com a criação de uma classe de modelo Manufacturer (fabricante) e um exemplo simples de objeto para conversor XML:

public class Manufacturer
{
        public string Name { get; set; }
        public string City { get; set; }
        public int Year { get; set; }
}
Enter fullscreen mode Exit fullscreen mode
public static class ManufacturerDataProvider
{
    public List<Manufacturer> GetData() =>
       new List<Manufacturer>
       {
            new Manufacturer { City = "Italy", Name = "Alfa Romeo", Year = 2016 },
            new Manufacturer { City = "UK", Name = "Aston Martin", Year = 2018 },
            new Manufacturer { City = "USA", Name = "Dodge", Year = 2017 },
            new Manufacturer { City = "Japan", Name = "Subaru", Year = 2016 },
            new Manufacturer { City = "Germany", Name = "BMW", Year = 2015 }
       };
}
Enter fullscreen mode Exit fullscreen mode
public class XmlConverter
{
    public XDocument GetXML()
    {
        var xDocument = new XDocument();
        var xElement = new XElement("Manufacturers");
        var xAttributes = ManufacturerDataProvider.GetData()
            .Select(m => new XElement("Manufacturer", 
                                new XAttribute("City", m.City),
                                new XAttribute("Name", m.Name),
                                new XAttribute("Year", m.Year)));

        xElement.Add(xAttributes);
        xDocument.Add(xElement);

        Console.WriteLine(xDocument);

        return xDocument;
    }
}
Enter fullscreen mode Exit fullscreen mode

Como podemos ver, este é um código bastante simples. Estamos coletando dados do fabricante, criando um elemento raiz do fabricante e todos os subelementos do fabricante com seus atributos.

Depois disso, estamos imprimindo os resultados na janela do console para mostrar a aparência do XML final.

Esta é a aparência do xDocument :

Saída

Agora vamos implementar uma classe JsonConverter:

public class JsonConverter
{
    private IEnumerable<Manufacturer> _manufacturers;

    public JsonConverter(IEnumerable<Manufacturer> manufacturers)
    {
        _manufacturers = manufacturers;
    }

    public void ConvertToJson()
    {
        var jsonManufacturers = JsonConvert.SerializeObject(_manufacturers, Formatting.Indented);

        Console.WriteLine("\nPrinting JSON list\n");
        Console.WriteLine(jsonManufacturers);
    }
}
Enter fullscreen mode Exit fullscreen mode

Este código é ainda mais simples porque apenas serializamos nossa lista de fabricantes em um formato JSON.

Claro, para que a serialização funcione, precisamos instalar a biblioteca Newtonsoft.Json, então não se esqueça de instala-la.

Excelente, temos nossa funcionalidade JSON e a interface XML fornecida. Mas agora, precisamos resolver um problema real. Como combinar essas duas interfaces para realizar nossa tarefa, que é converter fabricantes do formato XML para JSON.

Implementação do Adapter

Como podemos ver neste caso, não há nenhuma maneira de passar um xDocument para a classe JsonConverter e não deveria haver. Então precisamos criar a classe adapter que fará com que essas duas interfaces funcionem juntas.

Para fazer isso, vamos começar criando uma interface IXmlToJson para definir o comportamento de nossa classe adapter:

public interface IXmlToJson
{
    void ConvertXmlToJson();
}
Enter fullscreen mode Exit fullscreen mode

E então, vamos continuar com a classe XmlToJsonAdapter que implementará a interface IXmlToJson:

public class XmlToJsonAdapter : IXmlToJson
{
    private readonly XmlConverter _xmlConverter;

    public XmlToJsonAdapter(XmlConverter xmlConverter)
    {
        _xmlConverter = xmlConverter;
    }

    public void ConvertXmlToJson()
    {
        var manufacturers = _xmlConverter.GetXML()
                .Element("Manufacturers")
                .Elements("Manufacturer")
                .Select(m => new Manufacturer
                             {
                                City = m.Attribute("City").Value,
                                Name = m.Attribute("Name").Value,
                                Year = Convert.ToInt32(m.Attribute("Year").Value)
                             });

        new JsonConverter(manufacturers)
            .ConvertToJson();
    }
}
Enter fullscreen mode Exit fullscreen mode

Excelente. Criamos nossa classe adapter que converte o objeto de documento Xml na lista de fabricantes e fornece essa lista para a classe JsonConverter.

Portanto, como você pode ver, habilitamos a compatibilidade entre duas interfaces completamente diferentes apenas introduzindo uma classe adapter em nosso projeto.

Agora, podemos fazer uma chamada para esta classe adapter da nossa classe de cliente:

public class Program
{
   public static void Main(string[] args)
    {
        var xmlConverter = new XmlConverter();
        var adapter = new XmlToJsonAdapter(xmlConverter);
        adapter.ConvertXmlToJson();
    }
}
Enter fullscreen mode Exit fullscreen mode

Assim que iniciarmos nosso aplicativo, veremos o seguinte resultado:

Saída

Muito legal, não é?

E assim Concluímos nossa implementação.

Quando usar o Adapter

Devemos usar uma classe Adapter sempre que quisermos trabalhar com uma classe existente, mas que sua interface não é compatível com o resto do nosso código. Basicamente, o padrão Adapter é uma camada intermediária que serve como um tradutor entre o código implementado em nosso projeto e alguma classe de terceiros ou qualquer outra classe com uma interface diferente.

Além disso, devemos usar o Adapter quando quisermos reutilizar classes existentes de nosso projeto, quando elas não possuem uma funcionalidade comum. Ao usar o padrão Adapter neste caso, não precisamos estender cada classe separadamente e criar um código redundante.

Conclusão

O padrão Adapter é bastante comum no mundo do C# e é bastante usado quando temos que adaptar algumas classes existentes para uma nova interface. Pode aumentar a complexidade do código essas classes adicionais (adaptadoras), mas vale a pena o esforço com certeza.

💖 💪 🙅 🚩
evertonandrade
Everton Andrade

Posted on October 4, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related