Menu
Coddy logo textTech

Mixin vs Herencia

Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy — lección 54 de 110.

Ahora que has aprendido cómo funcionan los mixins, aclaremos cuándo usarlos en lugar de la herencia. La diferencia clave radica en la relación que expresan.

La herencia representa una relación "es-un". Un Dog es un Animal. La subclase es una versión especializada del padre, y solo puedes extender una clase.

Los mixins, por otro lado, representan una relación "puede-hacer". Un Dog puede nadar, pero nadar no es lo que define a un perro.

// Herencia: Dog ES un Animal
class Animal {
  String name;
  Animal(this.name);
}

class Dog extends Animal {
  Dog(String name) : super(name);
}

// Mixin: Dog PUEDE nadar (pero no está definido por nadar)
mixin Swimming {
  void swim() => print('Swimming');
}

class Dog extends Animal with Swimming {
  Dog(String name) : super(name);
}

Usa la herencia cuando las clases compartan una identidad fundamental y necesites constructores en el padre. Usa mixins cuando quieras añadir capacidades a clases que no comparten un ancestro común.

CaracterísticaHerenciaMixin
Relaciónes-unpuede-hacer
LímiteSolo un padreMúltiples mixins
ConstructoresPermitidoNo permitido
Caso de usoEspecializaciónComportamiento compartido

¿La mejor parte? Puedes combinar ambos: extender una clase y mezclar múltiples capacidades, dándole a tus clases exactamente las características que necesitan.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de trabajadores que demuestre cuándo usar la herencia frente a los mixins. Crearás una clase base para la relación "es-un" (is-a) y mixins para las capacidades de "puede-hacer" (can-do), luego los combinarás para mostrar cómo ambos enfoques funcionan juntos.

Organizarás tu código en tres archivos:

  • worker.dart: Define tu clase base que establece la identidad central de todos los trabajadores:
    • Una clase Worker con las propiedades String name y String department. Incluye un constructor que reciba ambos valores. Añade un método introduce() que imprima '$name works in $department'
  • skills.dart: Define mixins que representen las capacidades que los trabajadores pueden tener (las relaciones "puede-hacer"):
    • Un mixin CanCode con un método writeCode() que imprima 'Writing code...'
    • Un mixin CanDesign con un método createDesign() que imprima 'Creating design...'
    • Un mixin CanManage con un método leadTeam() que imprima 'Leading the team...'
  • main.dart: Importa ambos archivos y crea tipos de trabajadores especializados que combinen la herencia con los mixins:
    • Una clase Developer que extienda de Worker y use el mixin CanCode
    • Una clase TechLead que extienda de Worker y use los mixins CanCode y CanManage
    • Crea un Developer llamado 'Alice' en el departamento 'Engineering'
    • Crea un TechLead llamado 'Bob' en el departamento 'Engineering'
    • Para Alice: llama a introduce() y luego a writeCode()
    • Imprime una línea vacía
    • Para Bob: llama a introduce(), luego a writeCode() y después a leadTeam()

Observa cómo tanto Developer como TechLead son trabajadores (herencia), pero pueden hacer cosas diferentes (mixins). El TechLead combina múltiples capacidades sin necesidad de herencia múltiple.

Salida esperada:

Alice works in Engineering
Writing code...

Bob works in Engineering
Writing code...
Leading the team...

Hoja de referencia

La herencia representa una relación "es-un" (una subclase es una versión especializada del padre), mientras que los mixins representan una relación "puede-hacer" (añadiendo capacidades sin definir una identidad).

// Inheritance: Dog IS an Animal
class Animal {
  String name;
  Animal(this.name);
}

class Dog extends Animal {
  Dog(String name) : super(name);
}

// Mixin: Dog CAN swim
mixin Swimming {
  void swim() => print('Swimming');
}

class Dog extends Animal with Swimming {
  Dog(String name) : super(name);
}
CaracterísticaHerenciaMixin
Relaciónes-unpuede-hacer
LímiteSolo un padreMúltiples mixins
ConstructoresPermitidosNo permitidos
Caso de usoEspecializaciónComportamiento compartido

Puedes combinar ambos enfoques: extender una clase y mezclar múltiples capacidades:

class TechLead extends Worker with CanCode, CanManage {
  TechLead(String name, String department) : super(name, department);
}

Pruébalo tú mismo

import 'worker.dart';
import 'skills.dart';

// TODO: Crea una clase Developer que extienda de Worker y use el mixin CanCode

// TODO: Crea una clase TechLead que extienda de Worker y use los mixins CanCode y CanManage

void main() {
  // TODO: Crea un Developer llamado 'Alice' en el departamento 'Engineering'
  
  // TODO: Llama a introduce() y luego a writeCode() para Alice
  
  // TODO: Imprime una línea vacía
  
  // TODO: Crea un TechLead llamado 'Bob' en el departamento 'Engineering'
  
  // TODO: Llama a introduce(), writeCode(), y luego a leadTeam() para Bob
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos