Padrão - Adapter
Tags: javascript, cleancode, programming, architecture
Published: 2023-01-24 13:45:21

![Pattern Adapter](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rwkmr9s49cub132i5gva.png)

O padrão Adapter é um dos padrões de projeto estruturais que permite que interfaces incompatíveis trabalhem juntas. Ele foi introduzido no livro "Design Patterns: Elements of Reusable Object-Oriented Software" de Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides, conhecido como "Gang of Four" (GoF) em 1994. 

O padrão Adapter é um dos padrões de projeto estruturais que permite que duas interfaces incompatíveis trabalhem juntas. Ele faz isso criando uma classe intermediária, chamada Adapter, que traduz a interface de uma classe para outra.

Existem dois tipos de Adapter: o Adapter Classe e o Adapter Objeto.

No Adapter Classe, uma classe é criada que herda de ambas as classes (a classe existente e a classe de destino) e implementa a interface de destino. Essa classe intermediária, então, pode ser usada para adaptar a classe existente para a classe de destino.

No Adapter Objeto, uma instância de uma classe existente é encapsulada dentro de uma nova classe que implementa a interface de destino. Dessa forma, essa nova classe pode adaptar a classe existente para a classe de destino.


O padrão Adapter pode ser usado em várias situações, algumas das quais incluem:

- Quando você tem uma classe existente que precisa ser reutilizada, mas sua interface não é compatível com a classe que a está usando.
- Quando você quer criar uma classe intermediária para traduzir os dados de uma classe para outra, sem afetar as classes existentes.
- Quando você precisa trabalhar com várias classes que possuem interfaces semelhantes, mas não idênticas.
- Quando você deseja criar uma interface para uma classe legada, para que possa ser usada por outras classes sem modificar a classe legada.
- Quando você precisa trabalhar com classes de diferentes bibliotecas ou frameworks que possuem interfaces incompatíveis.
- Enfim, o padrão Adapter pode ser usado em qualquer situação em que é necessário adaptar ou traduzir uma interface para que possa ser usada por outra classe.

Segue abaixo um simples exemplo de código usando o padrão Adapter.

```js
class RequestAdapter {
  specificRequest() {
    return "Adapter request";
  }
}

class TargetRequest {
  request() {
    return "Target request";
  }
}

class Adapter extends TargetRequest {
  constructor() {
    super();
    this.requestAdapter = new RequestAdapter();
  }

  request() {
    return this.requestAdapter.specificRequest();
  }
}

const target = new TargetRequest();
console.log(target.request()); // "Adapter request"

const adapter = new Adapter();
console.log(adapter.request()); // "Target request"
```

Neste exemplo, temos uma classe RequestAdapter com um método específico specificRequest() que retorna "Adapter request". Temos também uma classe TargetRequest com um método request() que retorna "Target request".

A classe Adapter herda de TargetRequest e contém uma instância de RequestAdapter. O método request() na classe Adapter é reescrito para chamar o método specificRequest() na instância de Adaptee e retornar o resultado.

Ao criar uma instância de TargetRequest e chamar o método request(), ele retorna "Target request". Ao criar uma instância de Adapter e chamar o método request(), ele retorna "Adapter request", pois está chamando o método específico na instância RequestAdapter.

Dessa forma, a classe Adapter está adaptando a interface da classe RequestAdapter para atender à interface da classe TargetRequest, sem modificar as classes existentes.

_Simples, né ?_

Imagine outro cenário no qual precisa realizar uma busca alguns posts em uma API enquanto o time de desenvolvimento constrói o relacionamento entre os post com o usuário mas teria que mocar a outra request.

Segue a solução abaixo:

```js

class RequestAdapter {
  async getPosts() {
    return fetch('https://jsonplaceholder.typicode.com/posts/1')
      .then((response) => response.json())
  }
}

class TargetRequest {
  request() {
    return { user: { id: 1, name: 'mock', email: 'mock.@gmail.com' } };
  }
}

class Adapter extends TargetRequest {
  constructor() {
    super();
    this.requestAdapter = new RequestAdapter();
  }

  request() {
    return this.requestAdapter.getPosts();
  }
}

const target = new TargetRequest();
console.log(target.request()); // { user: { id: 1, name: 'mock', email: 'mock.@gmail.com' } }

const adapter = new Adapter();
adapter.request().then(response => console.log(response));
/*
{
  userId: 1,
  id: 1,
  title: "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
  body: "quia et suscipit\nsuscipit...
}
*/

```

Neste exemplo, temos uma classe RequestAdapter com um método específico getPosts() que usa Fetch para fazer uma solicitação GET e retorna os dados da resposta. Temos também uma classe Target com um método request() que retorna um objeto simples { user: { id: 1, name: 'mock', email: 'mock.@gmail.com' } }.

A classe Adapter herda de TargetRequest e contém uma instância de RequestAdapter. O método request() na classe Adapter é reescrito para chamar o método getPosts() na instância de RequestAdapter e retornar o resultado.

Ao criar uma instância de TargetRequest e chamar o método request(), ele retorna { user: { id: 1, name: 'mock', email: 'mock.@gmail.com' } }. Ao criar uma instância de Adapter e chamar o método request(), ele retorna os dados da resposta da solicitação GET realizada por meio do Fetch.

Dessa forma, a classe Adapter está adaptando a interface da classe RequestAdapter para atender à interface da classe TargetRequest, sem modificar as classes existentes.

Existem várias vantagens em usar o padrão Adapter, algumas das quais incluem:

- **Reutilização de código:** O padrão Adapter permite que você reutilize código existente sem modificá-lo. Isso pode ser útil quando você tem uma classe existente que é valiosa, mas sua interface não é compatível com a classe que a está usando.
- **Isolamento de mudanças:** O Adapter permite que você faça mudanças em uma classe sem afetar as outras classes. Isso pode ser útil quando você precisa atualizar ou corrigir uma classe existente, mas não quer afetar as outras classes que a estão usando.
- **Facilidade de manutenção:** O padrão Adapter torna mais fácil manter o código, pois as classes ficam isoladas e as dependências ficam claras. Isso pode ajudar a identificar problemas e fazer alterações no código mais facilmente.
- **Flexibilidade:** O padrão Adapter é flexível e pode ser usado em várias situações, como trabalhar com classes de diferentes bibliotecas ou frameworks, ou criar uma interface para uma classe legada.
- **Abstração:** O padrão Adapter ajuda a abstrair as diferenças entre as interfaces, facilitando a interação entre classes diferentes.

**Conclusão**

Enfim, usar o padrão Adapter permite reutilizar código existente, isolar mudanças, facilitar a manutenção, aumentar a flexibilidade e abstrair as diferenças entre as interfaces. Isso pode ajudar a manter o código limpo, fácil de entender e escalável.

Espero ter ajudado, até a próxima.