Adapter
Problema
Sección titulada «Problema»Dos proveedores que resuelven el mismo problema (cobrar un pago, mandar un SMS) casi nunca tienen la misma interfaz. Sin Adapter, el código que los usa termina lleno de if (proveedor === 'stripe') { ... } else { ... }. Adapter traduce cada proveedor a una interfaz común una sola vez, en un solo lugar, y el resto de la app deja de saber qué hay detrás.
Interfaz común
Sección titulada «Interfaz común»export interface PaymentProvider { charge( amountCents: number, currency: string ): Promise<{ id: string; status: "paid" | "failed" }>}Adapter para Stripe
Sección titulada «Adapter para Stripe»import Stripe from "stripe"import type { PaymentProvider } from "./payment-provider"
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!)
export const stripeAdapter: PaymentProvider = { async charge(amountCents, currency) { const intent = await stripe.paymentIntents.create({ amount: amountCents, currency, confirm: true }) return { id: intent.id, status: intent.status === "succeeded" ? "paid" : "failed" } }}Adapter para un proveedor local
Sección titulada «Adapter para un proveedor local»import { crearCobro } from "proveedor-local-sdk"import type { PaymentProvider } from "./payment-provider"
export const localProviderAdapter: PaymentProvider = { async charge(amountCents, currency) { const resultado = await crearCobro({ monto: amountCents / 100, moneda: currency }) return { id: resultado.referencia, status: resultado.aprobado ? "paid" : "failed" } }}El SDK de Stripe devuelve status: 'succeeded', el proveedor local devuelve aprobado: boolean. Ninguno de los dos coincide con la interfaz que definió la app — cada adapter absorbe esa diferencia.
async function cobrarPedido(provider: PaymentProvider, pedido: Pedido) { const resultado = await provider.charge(pedido.totalCents, pedido.moneda) if (resultado.status === "failed") throw new Error("Pago rechazado") return resultado.id}
// El caller elige el adapter, pero cobrarPedido no sabe cuál es.await cobrarPedido(stripeAdapter, pedido)Cuándo NO usarlo
Sección titulada «Cuándo NO usarlo»Si controlas ambos lados de la integración (tu propio código en los dos extremos), suele ser más simple cambiar uno de los dos para que las interfaces coincidan, en vez de mantener una capa de traducción permanente. Adapter se justifica cuando uno de los lados es código externo que no puedes (o no quieres) tocar.