El patrón Adaptador permite que componentes con interfaces distintas trabajen juntos sin modificar su código. En esta guía encontrarás ejemplos en TypeScript para integrar APIs incompatibles, refactorizar código legacy y crear integraciones mantenibles.
January 7, 2026 (3mo ago) — last updated March 7, 2026 (1mo ago)
Patrón Adaptador en TypeScript — Guía práctica
Guía práctica del patrón Adaptador en TypeScript: conecta APIs incompatibles, refactoriza código legacy y crea integraciones mantenibles.
← Back to blog
Patrón Adaptador en TypeScript — Guía práctica
Explora el patrón Adaptador con ejemplos reales en TypeScript. Conecta APIs incompatibles, refactoriza código legacy y crea integraciones mantenibles.
Introducción
El patrón de diseño Adaptador actúa como un intermediario que permite que dos sistemas con interfaces distintas se comuniquen sin modificar su código fuente original. Aplicado correctamente, protege la lógica central de tu aplicación y facilita la modernización incremental de sistemas legacy y la integración de APIs externas1.
Por qué tu base de código necesita el patrón Adaptador

Imagina que intentas enchufar un portátil comprado en Canadá a una toma europea: el hardware funciona, pero las interfaces no coinciden. Lo mismo ocurre en software cuando un servicio devuelve XML y tu frontend espera JSON, o cuando una pasarela de pago expone una API propia y tu aplicación necesita una interfaz estándar.
Hoy rara vez construimos todo desde cero; muchas aplicaciones integran librerías de terceros y sistemas legacy, lo que obliga a afrontar incompatibilidades de interfaz y riesgos de deuda técnica4. El patrón Adaptador te permite encapsular la traducción en una clase dedicada, reduciendo duplicación de lógica, acoplamiento y esfuerzo de mantenimiento2.
El patrón Adaptador convierte la interfaz de una clase en otra interfaz que los clientes esperan, permitiendo que componentes incompatibles trabajen juntos3.
Beneficios clave
- Centraliza la lógica de traducción en una única clase.
- Protege la lógica de negocio de detalles de integración.
- Facilita la migración incremental y la sustitución de dependencias.
- Mejora la testabilidad mediante mocks del Adaptee.
Cómo funciona en la práctica
Cuatro roles hacen posible el patrón:
- Cliente: el código que solicita un servicio.
- Target: la interfaz que espera el Cliente.
- Adaptee: el componente existente con una interfaz incompatible.
- Adaptador: implementa Target y traduce llamadas al Adaptee.

El Cliente sólo interactúa con Target; el Adaptador traduce en silencio para el Adaptee. Este enfoque respeta el Principio Abierto/Cerrado: para integrar un nuevo servicio basta con escribir un nuevo adaptador sin tocar el código cliente.
Ejemplos reales en TypeScript
A continuación hay dos ejemplos prácticos que reflejan problemas comunes: adaptar una API XML legacy y estandarizar una pasarela de pagos.
Ejemplo 1: Adaptando una API XML legacy a JSON
Escenario: el frontend espera JSON, pero la única fuente disponible devuelve XML. Creamos una interfaz IUserService y un adaptador que la implementa.
// Adaptee: servicio legacy con interfaz incompatible
class LegacyUserService {
fetchUsersXML(): string {
return `
<users>
<user id="1">
<name>Alice</name>
<email>alice@example.com</email>
</user>
<user id="2">
<name>Bob</name>
<email>bob@example.com</email>
</user>
</users>
`;
}
}
interface IUser {
id: number;
name: string;
email: string;
}
interface IUserService {
getUsers(): Promise<IUser[]>;
}
class UserServiceAdapter implements IUserService {
private adaptee: LegacyUserService;
constructor(legacyService: LegacyUserService) {
this.adaptee = legacyService;
}
async getUsers(): Promise<IUser[]> {
const xmlData = this.adaptee.fetchUsersXML();
// En producción usa un parser robusto (por ejemplo, xml2js).
console.log("Translating XML to JSON...");
return [
{ id: 1, name: "Alice", email: "alice@example.com" },
{ id: 2, name: "Bob", email: "bob@example.com" },
];
}
}
Este adaptador permite que el cliente use IUserService sin conocer el XML.
Ejemplo 2: Estandarizando una pasarela de pago
Escenario: tu aplicación usa una interfaz IPaymentProcessor, pero la pasarela PayWizard expone métodos distintos. El adaptador mapea llamadas estándar a la API de PayWizard.
class PayWizard {
startTransaction(amount: number, cardDetails: string): string {
console.log(`PayWizard: Initiating transaction for $${amount}.`);
const transactionId = "pw_" + Math.random().toString(36).substr(2, 9);
return transactionId;
}
verifyPaymentStatus(transactionId: string): boolean {
console.log(`PayWizard: Verifying status for ${transactionId}.`);
return true;
}
}
interface IPaymentProcessor {
processPayment(amount: number, cardInfo: string): Promise<string>;
checkStatus(id: string): Promise<boolean>;
}
class PayWizardAdapter implements IPaymentProcessor {
private payWizard: PayWizard;
constructor() {
this.payWizard = new PayWizard();
}
async processPayment(amount: number, cardInfo: string): Promise<string> {
console.log("Adapter: Translating 'processPayment' to 'startTransaction'.");
return this.payWizard.startTransaction(amount, cardInfo);
}
async checkStatus(id: string): Promise<boolean> {
console.log("Adapter: Translating 'checkStatus' to 'verifyPaymentStatus'.");
return this.payWizard.verifyPaymentStatus(id);
}
}
Usar adaptadores mantiene el código de la aplicación consistente entre proveedores y facilita el cambio de proveedor sin tocar la lógica cliente.
Refactorizando código legacy con adaptadores

Todo proyecto eventualmente se enfrenta a código legacy; el patrón Adaptador permite envolver sistemas antiguos con una interfaz moderna y migrar el código cliente de forma incremental4.
Plan de migración práctico:
- Define la interfaz Target que quieres que consuman los clientes.
- Crea la clase Adaptador que implemente Target y acepte el Adaptee legacy.
- Implementa la lógica de traducción y añade tests unitarios.
- Migra el código cliente de forma gradual.
Las herramientas de IA pueden acelerar la generación de boilerplate, pero las decisiones arquitectónicas y los mapeos críticos deben ser revisados por el equipo. Escribe tests de mapeo y añade benchmarks cuando el adaptador esté en rutas críticas.
Elegir entre Adaptador y otros patrones
- Adaptador: convierte una interfaz en otra.
- Decorator: añade responsabilidades sin cambiar la interfaz.
- Proxy: controla acceso, caching o inicialización perezosa.
- Façade: simplifica un subsistema complejo tras una interfaz única.
Resumen práctico
| Patrón | Intención principal | Cuándo usar |
|---|---|---|
| Adapter | Convertir una interfaz a otra | Cuando una clase existente debe trabajar con un cliente incompatible. |
| Decorator | Añadir responsabilidades | Cuando quieres extender comportamiento dinámicamente. |
| Proxy | Controlar acceso | Cuando necesitas lazy loading, control de acceso o logging. |
| Façade | Simplificar subsistemas | Cuando quieres un único punto de entrada a comportamiento complejo. |
Llevar el patrón Adaptador a tu equipo
Para evitar su uso excesivo, establece normas claras:
- Documentación: cada adaptador debe incluir un README que describa el Adaptee, la interfaz Target y el mapeo.
- Pruebas: exige tests unitarios para la lógica de traducción y pruebas de integración con la dependencia real.
- Rendimiento: mide adaptadores en rutas calientes y añade benchmarks cuando sea necesario.
Automatiza chequeos en CI para garantizar plantillas y pruebas, y publica ejemplos y plantillas en la documentación interna, por ejemplo, en tu guía de modernización de sistemas.
Preguntas rápidas (Q&A)
¿Cuándo usar un adaptador en vez de reescribir un componente?
Usa un adaptador cuando el componente existente funciona pero su interfaz no coincide con tus necesidades, especialmente con sistemas legacy estables o APIs de terceros que no controlas. Reescribe sólo si la dependencia tiene errores críticos o carece de funcionalidades necesarias.
¿Los adaptadores afectan el rendimiento?
Normalmente añaden una sobrecarga muy pequeña —una llamada extra o una conversión de datos— que suele ser insignificante frente a latencia de red o E/S. Para rutas sensibles a la latencia, mide y optimiza el adaptador.
¿Cómo testear adaptadores?
Escribe tests unitarios centrados en los mapeos entre Target y Adaptee, mockeando el Adaptee cuando corresponda. Complementa con tests de integración para validar el comportamiento con la dependencia real.
La IA escribe código.Tú lo haces durar.
En la era de la aceleración de la IA, el código limpio no es solo una buena práctica — es la diferencia entre sistemas que escalan y bases de código que colapsan bajo su propio peso.