Menu
Coddy logo textTech

Fundamentos del polimorfismo

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

El polimorfismo significa "muchas formas": es la capacidad de tratar objetos de diferentes clases a través de una interfaz común. Cuando tienes una referencia de clase padre, esta puede apuntar a cualquier objeto de clase hija, y se llama al método correcto basándose en el tipo de objeto real.

Esto es potente porque puedes escribir código que funcione con el tipo padre y, aun así, maneje automáticamente todos los tipos hijos correctamente:

class Animal {
  void speak() => print('Some sound');
}

class Dog extends Animal {
  @override
  void speak() => print('Woof!');
}

class Cat extends Animal {
  @override
  void speak() => print('Meow!');
}

void main() {
  Animal myPet = Dog();  // Tipo padre, objeto hijo
  myPet.speak();  // Salida: Woof!
  
  myPet = Cat();  // Misma variable, objeto diferente
  myPet.speak();  // Salida: Meow!
}

La variable myPet está declarada como Animal, pero contiene un Dog o Cat. Cuando se llama a speak(), Dart observa el tipo de objeto real en tiempo de ejecución y llama al método sobrescrito correspondiente.

Esto te permite escribir funciones flexibles que funcionan con cualquier subclase:

void makeAllSpeak(List<Animal> animals) {
  for (var animal in animals) {
    animal.speak();  // Cada animal habla a su manera
  }
}

void main() {
  var pets = [Dog(), Cat(), Dog()];
  makeAllSpeak(pets);
  // Salida: Woof! Meow! Woof!
}

La función no necesita saber sobre Dog o Cat; simplemente funciona con Animal. Esto hace que tu código sea más extensible, ya que agregar nuevos tipos de animales no requiere cambios en las funciones existentes.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de instrumentos musicales que demuestre el polimorfismo en acción. Crearás una clase base Instrument y varios tipos de instrumentos, luego escribirás una función que pueda hacer que cualquier colección de instrumentos toque junta, sin conocer sus tipos específicos.

Organizarás tu código en dos archivos:

  • instruments.dart: Define tu jerarquía de instrumentos aquí:
    • Una clase Instrument con una propiedad String name y un constructor. Incluye un método play() que imprima '$name makes a sound'
    • Una clase Guitar que extienda de Instrument y sobrescriba play() para imprimir '$name strums melodically'
    • Una clase Drum que extienda de Instrument y sobrescriba play() para imprimir '$name beats rhythmically'
    • Una clase Piano que extienda de Instrument y sobrescriba play() para imprimir '$name plays harmoniously'
    También crea una función performConcert(List<Instrument> instruments) que imprima 'Concert begins!', luego itere a través de la lista llamando a play() en cada instrumento, y finalmente imprima 'Concert ends!'
  • main.dart: Importa tu archivo de instrumentos y demuestra el polimorfismo creando una banda mixta:
    • Crea una lista de tipo List<Instrument> que contenga una Guitar llamada 'Acoustic', un Drum llamado 'Snare', y un Piano llamado 'Grand'
    • Pasa esta lista a performConcert()

Observa cómo performConcert() trabaja con el tipo padre Instrument, pero cada instrumento toca a su manera única. Esto es el polimorfismo: la misma llamada al método produce un comportamiento diferente basado en el tipo de objeto real.

Salida esperada:

Concert begins!
Acoustic strums melodically
Snare beats rhythmically
Grand plays harmoniously
Concert ends!

Hoja de referencia

El polimorfismo significa "muchas formas"; permite tratar objetos de diferentes clases a través de una interfaz común. Una referencia de clase padre puede apuntar a cualquier objeto de clase hija, y se llama al método correcto basándose en el tipo de objeto real en tiempo de ejecución.

Ejemplo básico de polimorfismo:

class Animal {
  void speak() => print('Some sound');
}

class Dog extends Animal {
  @override
  void speak() => print('Woof!');
}

class Cat extends Animal {
  @override
  void speak() => print('Meow!');
}

void main() {
  Animal myPet = Dog();  // Tipo padre, objeto hijo
  myPet.speak();  // Salida: Woof!
  
  myPet = Cat();  // Misma variable, objeto diferente
  myPet.speak();  // Salida: Meow!
}

El polimorfismo permite funciones flexibles que funcionan con cualquier subclase:

void makeAllSpeak(List<Animal> animals) {
  for (var animal in animals) {
    animal.speak();  // Cada animal habla a su manera
  }
}

void main() {
  var pets = [Dog(), Cat(), Dog()];
  makeAllSpeak(pets);
  // Salida: Woof! Meow! Woof!
}

La función trabaja con el tipo padre Animal sin necesidad de conocer las clases hijas específicas como Dog o Cat. Esto hace que el código sea más extensible: añadir nuevos tipos no requiere cambios en las funciones existentes.

Pruébalo tú mismo

import 'instruments.dart';

void main() {
  // TODO: Crear una List<Instrument> que contenga:
  // - Una Guitar llamada 'Acoustic'
  // - Un Drum llamado 'Snare'
  // - Un Piano llamado 'Grand'
  
  
  // TODO: Llamar a performConcert() con tu lista de instrumentos
  
}
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