Ver todas las comparaciones
poo

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

Aspectoimplementsextends
Qué estableceUn contrato (interfaz)Una jerarquía (herencia)
Código que obtienesNada — tú lo escribes todoTodo — lo heredas del padre
Cuantos puedes usarVarios (class A implements X, Y, Z)Solo uno (class A extends B)
Estado internoNo, las interfaces no tienen estadoSí, heredas propiedades con valores
Modificadores de accesoNo aplica (solo declaraciones)Heredas public y protected
ConstructoresNo hay constructores en interfacesPuedes heredar y llamar con super()
Relación semántica”Puede hacer” (capability)“Es un” (identity)
EstabilidadAlta — cambiar la interfaz rompe implementacionesMedia — cambiar el padre puede romper hijos
Lenguajes típicosJava, 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.

  • extends construye jerarquías. Modela “es un” (un Perro es un Animal).
  • implements construye 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.