O padrão de design Adapter (ou Adaptador), na sua forma de adaptação de classe, tem como objetivo principal permitir que interfaces incompatíveis trabalhem juntas.

Ele age como um intermediário que traduz chamadas feitas em uma interface para uma forma que outra interface entenda. Especificamente, o padrão Adapter de classe tenta resolver os seguintes problemas:

  1. Compatibilidade de Interfaces: Em muitos sistemas, especialmente aqueles que envolvem a integração de componentes de terceiros ou legados, frequentemente nos deparamos com classes que têm interfaces incompatíveis. O Adapter permite que essas classes colaborem sem alterar seus códigos fontes.

  2. Reutilização de Código Existente: Quando temos bibliotecas ou módulos já existentes que oferecem funcionalidades úteis, mas suas interfaces não são compatíveis com o restante do nosso sistema, o Adapter nos permite reutilizar esse código existente, adaptando-o para trabalhar com as novas interfaces.

  3. Abstração e Encapsulamento: O Adapter fornece uma camada de abstração que encapsula a complexidade da adaptação. O cliente usa a interface do Adapter, enquanto este lida com a conversão para a interface do componente que está sendo adaptado.

  4. Flexibilidade e Extensibilidade: Ao separar a implementação específica e o código cliente, o padrão Adapter aumenta a flexibilidade e a possibilidade de estender o sistema com novos tipos de adaptadores para diferentes componentes, sem afetar o código existente.

Adaptação de Classe vs. Adaptação de Objeto

Existem duas variantes do padrão Adapter: adaptação de classe e adaptação de objeto.

A adaptação de classe usa a herança para adaptar uma interface à outra. Ela requer herança múltipla, que não é suportada em algumas linguagens de programação como Java. Portanto, em Java, a adaptação de objeto, que usa composição, é mais comum.

Exemplo de Adaptação de Classe

Em linguagens que suportam herança múltipla, como C++, o Adapter de classe pode ser implementado herdando tanto a interface que se deseja implementar (o alvo) quanto a classe que se deseja adaptar.

Por exemplo, se você tem uma interface Target com um método request() e uma classe Adaptee com um método specificRequest(), um Adapter de classe em C++ poderia parecer assim:

class Target {
public:
    virtual void request() = 0;
};
 
class Adaptee {
public:
    void specificRequest() {
        // Implementação específica
    }
};
 
class Adapter : public Target, private Adaptee {
public:
    void request() override {
        specificRequest();
    }
};

Neste exemplo, Adapter herda Target e Adaptee. Quando request() é chamado em um objeto Adapter, ele chama specificRequest() da classe Adaptee.