implements vs extends
Compara implements y extends, las dos formas de establecer relaciones entre clases en POO. implements define un contrato a cumplir, extends define una jerarquía de herencia.
Introducción
Si estás aprendiendo Programación Orientada a Objetos, te vas a topar con dos palabras clave bien parecidas: implements y extends. Se ven similares, se usan en contextos parecidos, pero resuelven problemas distintos.
Entender la diferencia entre ambos no es solo teoría — te va a ayudar a diseñar mejor tus clases y a escribir código que otros desarrolladores puedan leer y mantener sin pedirte explicaciones.
extends es para heredar. Una clase hija obtiene todo lo que tiene la clase padre: propiedades, métodos, lógica ya escrita. implements es para contratos. Una clase promete cumplir con lo que dice una interfaz, pero tiene que escribir el código ella misma.
Vamos a detallarlo.
¿Qué es implements?
implements es la palabra clave que usa una clase para decir “yo cumplo con esta interfaz”. Una interfaz solo declara métodos (y a veces propiedades), pero no escribe el código. La clase que implementa la interfaz es la que escribe la lógica real.
Piénsalo como un contrato: la interfaz dice qué hay que hacer, la clase dice cómo lo va a hacer.
interface Reproducible {
reproducir(): void;
pausar(): void;
detener(): void;
}
class Spotify implements Reproducible {
reproducir(): void {
console.log('Reproduciendo música desde la nube');
}
pausar(): void {
console.log('Pausando reproducción');
}
detener(): void {
console.log('Deteniendo y liberando recursos');
}
}
La ventaja: cualquier clase que implemente Reproducible va a tener esos tres métodos, sin importar cómo los implemente por dentro. Puedes tener Spotify, AppleMusic, YouTubeMusic, todos implementando la misma interfaz.
¿Qué es extends?
extends es para la herencia de clases. Una clase hija extiende a una clase padre, lo que significa que hereda todo su código: propiedades, métodos, lógica de negocios, todo. Luego puede agregar lo suyo propio o modificar lo que heredó.
class Animal {
constructor(public nombre: string) {}
moverse(): string {
return `${this.nombre} se está moviendo`;
}
}
class Perro extends Animal {
moverCola(): string {
return `${this.nombre} mueve la cola feliz`;
}
// Sobrescribe el método del padre
moverse(): string {
return `${this.nombre} corre en cuatro patas`;
}
}
const fido = new Perro('Fido');
console.log(fido.moverse()); // "Fido corre en cuatro patas"
console.log(fido.moverCola()); // "Fido mueve la cola feliz"
La gracia de extends es que no repites código. Todo lo que ya está en Animal, lo usa Perro sin tener que escribirlo de nuevo.
Diferencias clave
| Aspecto | implements | extends |
|---|---|---|
| Qué establece | Un contrato (interfaz) | Una jerarquía (herencia) |
| Código que obtienes | Nada — tú lo escribes todo | Todo — lo heredas del padre |
| Cuantos puedes usar | Varios (class A implements X, Y, Z) | Solo uno (class A extends B) |
| Estado interno | No, las interfaces no tienen estado | Sí, heredas propiedades con valores |
| Modificadores de acceso | No aplica (solo declaraciones) | Heredas public y protected |
| Constructores | No hay constructores en interfaces | Puedes heredar y llamar con super() |
| Relación semántica | ”Puede hacer” (capability) | “Es un” (identity) |
| Estabilidad | Alta — cambiar la interfaz rompe implementaciones | Media — cambiar el padre puede romper hijos |
| Lenguajes típicos | Java, TypeScript, PHP, C# | Java, TypeScript, PHP, C#, Kotlin |
¿Se pueden combinar?
Sí, y de hecho es muy común. Una clase puede extender a otra clase Y implementar una o varias interfaces.
interface Volador {
volar(): void;
}
interface Nadador {
nadar(): void;
}
class Animal {
constructor(public nombre: string) {}
}
class Pato extends Animal implements Volador, Nadador {
volar(): void {
console.log(`${this.nombre} está volando`);
}
nadar(): void {
console.log(`${this.nombre} está nadando`);
}
}
class Avion implements Volador {
volar(): void {
console.log('Avión despegando');
}
}
Aquí Pato hereda el nombre de Animal y además cumple con los contratos de Volador y Nadador. Bienvenido al poder del polimorfismo.
Errores comunes
Usar extends cuando deberías usar implements
// Mal: heredar comportamiento que no necesitas
class ConfiguracionDB extends BaseDeDatos {
// Pero ConfiguracionDB solo necesita leer un JSON
}
// Bien: implementar solo lo que necesitas
interface Configuracion {
cargar(): object;
guardar(config: object): void;
}
class ConfiguracionArchivo implements Configuracion {
cargar(): object {
return JSON.parse(fs.readFileSync('config.json', 'utf-8'));
}
guardar(config: object): void {
fs.writeFileSync('config.json', JSON.stringify(config));
}
}
Pensar que implements es lo mismo que extends
No, no es que implements sea “extends pero más light”. Son mecanismos diferentes. extends te da código funcionando; implements te da una lista de cosas que tienes que escribir tú.
Crear interfaces enormes
Si tu interfaz tiene 15 métodos, probablemente está mal diseñada. Mejor divídela en interfaces más chicas:
// Mal
interface TodoEnUno {
guardar(): void;
eliminar(): void;
exportar(): void;
validar(): boolean;
notificar(): void;
loggear(): void;
}
// Bien: interfaces pequeñas y específicas
interface Persistible {
guardar(): void;
eliminar(): void;
}
interface Exportable {
exportar(): void;
}
interface Validable {
validar(): boolean;
}
¿Y en lenguajes sin herencia múltiple?
Lenguajes como Java, TypeScript y PHP no permiten herencia múltiple con extends (una clase solo puede extender a una clase padre). Pero sí permiten implementar múltiples interfaces. Ahí está el chiste:
- extends: solo uno, porque tener dos padres causaría el “problema del diamante” (¿qué pasa si los dos padres tienen el mismo método?)
- implements: varios, porque las interfaces solo declaran métodos sin implementación, así que no hay conflicto
class C extends A, B { } // Error: herencia múltiple no permitida
class C implements X, Y, Z { } // OK: múltiples interfaces
Si necesitas reutilizar código de varias fuentes, algunos lenguajes ofrecen alternativas:
- PHP: Traits
- TypeScript/JavaScript: Mixins
- Java 8+: Default methods en interfaces
- C#: Default interface methods
Cuándo usar cuál
Usa extends cuando:
- Tu clase es una versión más específica de otra
- Necesitas reutilizar código ya escrito
- Tienes una jerarquía clara (Animal → Perro → Labrador)
- Quieres sobrescribir métodos del padre para cambiar comportamiento
Usa implements cuando:
- Necesitas asegurar que una clase cumpla con ciertos métodos
- Quieres que clases no relacionadas compartan el mismo comportamiento
- Diseñas para polimorfismo (código que funciona con cualquier implementación)
- Varias clases deben tener los mismos métodos pero con lógica diferente
- Usas Dependency Injection y quieres desacoplar implementaciones
Conclusión
La regla de oro: extends es lo que eres, implements es lo que sabes hacer.
extendsconstruye jerarquías. Modela “es un” (un Perro es un Animal).implementsconstruye capacidades. Modela “puede hacer” (un Perro puede ser Mascota).
Ambos son herramientas del diseño orientado a objetos. No hay uno mejor que otro — se usan para cosas distintas. Aprende a identificar cuándo necesitas heredar comportamiento y cuándo necesitas cumplir un contrato. Esa diferencia separa al dev que escribe código que funciona del que diseña código que escala.
Domina estos conceptos: implements, herencia, interfaces, y vas a escribir código POO con una claridad que tus compañeros te van a agradecer.