Resumo
Adapter é um padrão estrutural que converte a interface de uma classe em outra interface esperada pelo cliente. Ele permite que classes com interfaces incompatíveis trabalhem juntas sem modificar nenhuma das duas.
Em termos práticos: seu código fala uma linguagem, a API externa fala outra. O Adapter traduz no meio — e quando a API muda ou você troca de provedor, só o Adapter muda.
Problema que resolve
Integrar serviços externos diretamente no código de domínio cria acoplamento com algo que você não controla. Quando o SDK muda, quando você troca de provedor de e-mail, de pagamento ou de storage — o estrago se espalha por todo lugar onde o SDK foi chamado diretamente.
// SDK de e-mail chamado diretamente no domínio:
import { SendGrid } from "@sendgrid/mail";
async function notificarCliente(pedido: Pedido) {
const sg = new SendGrid(process.env.SENDGRID_KEY);
await sg.send({
to: pedido.email,
from: "noreply@empresa.com",
subject: "Pedido confirmado",
html: `<p>Seu pedido #${pedido.id} foi confirmado.</p>`,
});
}
// trocar de SendGrid para AWS SES = reescrever todas as funções que o usamAntes e depois
import { SendGrid } from "@sendgrid/mail";
// domínio conhece SendGrid diretamente
async function notificarCliente(pedido: Pedido) {
const sg = new SendGrid(process.env.SENDGRID_KEY);
await sg.send({
to: pedido.email,
from: "noreply@empresa.com",
subject: "Pedido confirmado",
html: `<p>Pedido #${pedido.id} confirmado.</p>`,
});
}// porta do domínio — interface que o domínio define:
interface EmailService {
enviar(params: { para: string; assunto: string; html: string }): Promise<void>;
}
// adapter — traduz para o SDK externo:
class SendGridAdapter implements EmailService {
private sg = new SendGrid(process.env.SENDGRID_KEY);
async enviar({ para, assunto, html }) {
await this.sg.send({ to: para, from: "noreply@empresa.com", subject: assunto, html });
}
}
// domínio só conhece a interface:
async function notificarCliente(pedido: Pedido, email: EmailService) {
await email.enviar({
para: pedido.email,
assunto: "Pedido confirmado",
html: `<p>Pedido #${pedido.id} confirmado.</p>`,
});
}
// trocar de SendGrid para AWS SES = criar SesAdapter, zero mudança no domínioQuando usar
- Integrar uma biblioteca ou API externa ao código de domínio.
- Você quer poder trocar de provedor (pagamento, e-mail, storage, analytics) sem reescrever o domínio.
- Testes precisam de uma implementação fake simples — o Adapter facilita criar um
EmailServiceInMemory. - Duas partes do sistema usam estruturas de dados incompatíveis e precisam se comunicar.
Quando não usar
- A integração é trivial e tem um único ponto de uso — a indireção pode custar mais do que vale.
- O "adaptado" já fala exatamente a linguagem do domínio — não há incompatibilidade real a resolver.
Onde aparece no dia a dia
- Pagamentos:
PagamentoServiceimplementado porStripeAdapter,MercadoPagoAdapter. - Storage:
ArquivoServiceimplementado porS3Adapter,LocalDiskAdapter. - Autenticação:
AuthProviderimplementado porFirebaseAdapter,Auth0Adapter. - Analytics:
TrackingServiceimplementado porMixpanelAdapter,AmplitudeAdapter. - Notificações push:
PushServiceimplementado porFCMAdapter,APNSAdapter.
Erros comuns
- Criar Adapters com lógica de negócio — o Adapter deve apenas traduzir, não decidir.
- Expor tipos do SDK externo na interface do Adapter — o domínio passa a depender do SDK indiretamente.
- Criar um Adapter para algo que nunca vai mudar e nunca precisará ser testado isoladamente.
Conceitos relacionados
- Acoplamento — o problema central que o Adapter reduz ao proteger o domínio de dependências externas.
- Strategy — frequentemente usado junto: Adapter adapta a interface, Strategy decide qual Adapter usar.
- Factory — factories criam e configuram Adapters sem expor os detalhes de instanciação.