Design Pattern Adapter em C#
Tags: design, patterns
Published: 2020-10-04 15:15:43

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:

```csharp
public class Manufacturer
{
		public string Name { get; set; }
		public string City { get; set; }
		public int Year { get; set; }
}
```

```csharp
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 }
       };
}
```

```csharp
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;
    }
}
```

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](https://i.ibb.co/4J95Qc8/Screenshot-20201024-101555.png)

Agora vamos implementar uma classe `JsonConverter`:

```csharp
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);
    }
}
```

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:

```csharp
public interface IXmlToJson
{
    void ConvertXmlToJson();
}
```

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

```csharp
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();
    }
}
```

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:

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

Assim que iniciarmos nosso aplicativo, veremos o seguinte resultado:

![Saída](https://i.ibb.co/H7c5RqK/Screenshot-20201024-100739.png)

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.