Dart: POO, Mixins y Herencia

Clases, constructores con nombre, mixins (with) y getters/setters con validación

🐾 Demo: Jerarquía de Animales

Objeto creado:

runtimeType
Pato (con mixin PuedeNadar)
descripcion (getter)
Rex tiene 3 años
hacerSonido()
Cuac cuac
nadar() — viene del mixin
chapoteando en el agua 🌊

Crea tu animal

class Animal {
  final String nombre;
  int _edad;

  Animal(this.nombre, this._edad);

  // Constructor con nombre: delega en el constructor principal  Animal.bebe(String nombre) : this(nombre, 0);

  String get descripcion => '$nombre tiene $_edad años';

  set actualizarEdad(int nuevaEdad) {
    if (nuevaEdad < 0) {
      throw ArgumentError(t('La edad no puede ser negativa'));
    }
    _edad = nuevaEdad;
  }

  String hacerSonido() => '...';
}

mixin PuedeNadar {
  String nadar() => 'chapoteando en el agua';
}

class Pato extends Animal with PuedeNadar {
  Pato(String nombre, int edad) : super(nombre, edad);

  @override
  String hacerSonido() => 'Cuac cuac';
}
💡 with (mixin) vs extends (herencia)

Con extends una clase solo puede heredar de UNA clase padre. Con with NombreMixin puedes "mezclar" comportamiento de varios mixins a la vez — por eso Pato puede heredar de Animal Y además ganar nadar() sin que Perro o Gato lo tengan.

📖 Factory Constructor (patrón singleton)

class ConfiguracionApp {
  static final ConfiguracionApp _instancia = ConfiguracionApp._interno();

  // El constructor normal está "oculto" (empieza por _)  ConfiguracionApp._interno();

  // El factory decide qué instancia devolver — aquí, siempre la misma  factory ConfiguracionApp() {
    return _instancia;
  }
}

final config1 = ConfiguracionApp();
final config2 = ConfiguracionApp();
print(identical(config1, config2)); // true: son el mismo objeto
💡 ¿Para qué sirve factory?

Un constructor factory no tiene por qué crear un objeto nuevo cada vez: puede devolver una instancia ya existente (singleton), devolver una subclase distinta según los parámetros, o construir el objeto a partir de un JSON validando datos antes.

🎯 Conceptos Clave

Constructores

  • Normal: Animal(this.nombre)
  • Con nombre: Animal.bebe(...)
  • factory: decide qué devolver

Mixins

  • mixin + with
  • Reutiliza comportamiento sin herencia única

Getters / Setters

  • get calcula un valor al leer
  • set puede validar al escribir

💪 Ejercicio Práctico

Amplía la jerarquía

  1. Crea un mixin PuedeVolar con un método volar() y aplícalo también a una nueva clase Paloma extends Animal.
  2. Añade un getter esAdulto que devuelva true si la edad es mayor o igual a 2.
  3. Crea un constructor factory Animal.desdeTexto(String csv) que reciba "nombre,edad" y construya el objeto parseando el texto.

Solución 1

mixin PuedeVolar {
  String volar() => 'volando por el cielo';
}

class Paloma extends Animal with PuedeVolar {
  Paloma(String nombre, int edad) : super(nombre, edad);
}

Solución 2

bool get esAdulto => _edad >= 2;

Solución 3

factory Animal.desdeTexto(String csv) {
  final partes = csv.split(',');
  return Animal(partes[0], int.parse(partes[1]));
}