Sobrescritura de métodos
Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy — lección 38 de 110.
La sobrescritura de métodos ocurre cuando una clase hija proporciona su propia implementación de un método que ya existe en la clase padre. Esto permite que las subclases personalicen el comportamiento heredado manteniendo la misma firma del método.
Cuando defines un método en una clase hija con el mismo nombre y parámetros que uno en la clase padre, la versión de la clase hija prevalece:
class Animal {
String name;
Animal(this.name);
void speak() {
print('$name makes a sound');
}
}
class Dog extends Animal {
Dog(String name) : super(name);
void speak() {
print('$name barks: Woof!');
}
}
void main() {
var animal = Animal('Generic');
var dog = Dog('Buddy');
animal.speak(); // Generic hace un sonido
dog.speak(); // Buddy ladra: ¡Guau!
}Cuando llamas a speak() en una instancia de Dog, Dart ejecuta la versión de Dog, no la de Animal. La clase hija ha sobrescrito el método de la clase padre.
También puedes combinar la sobrescritura con super para extender en lugar de reemplazar el comportamiento del padre:
class Cat extends Animal {
Cat(String name) : super(name);
void speak() {
super.speak(); // Llama primero a la versión del padre
print('$name also purrs');
}
}Este patrón permite construir sobre la funcionalidad existente. La regla clave es simple: el mismo nombre de método y parámetros en la clase hija reemplaza la implementación del padre cuando se llama en instancias de la hija.
Desafío
FácilVamos a construir un sistema de notificaciones que demuestre cómo las clases hijas pueden sobrescribir los métodos de los padres para personalizar el comportamiento. Crearás diferentes tipos de notificaciones que entregan mensajes de su propia manera única.
Organizarás tu código en dos archivos:
notification.dart: Define tu jerarquía de notificaciones aquí:- Una clase
Notification(el padre) con unString titleyString message. Incluye un constructor que tome ambos valores y un métodosend()que imprimaNotification: [title] - [message] - Una clase
EmailNotificationque extiendaNotificationy añada una propiedadString recipient. Sobrescribe el métodosend()para imprimirSending email to [recipient]: [title] - [message] - Una clase
PushNotificationque extiendaNotificationy añada una propiedadString deviceId. Sobrescribe el métodosend()para llamar primero alsend()del padre usandosuper, luego imprimePushed to device: [deviceId]en la siguiente línea
- Una clase
main.dart: Importa tu archivo de notificaciones y demuestra la sobrescritura de métodos en acción:- Crea una
Notificationbase con el título'Alert'y el mensaje'System update available' - Llama a su método
send() - Imprime una línea vacía
- Crea una
EmailNotificationcon el título'Welcome', el mensaje'Thanks for signing up!', y el destinatario'user@example.com' - Llama a su método
send() - Imprime una línea vacía
- Crea una
PushNotificationcon el título'Reminder', el mensaje'Meeting in 10 minutes', y el deviceId'DEVICE-001' - Llama a su método
send()
- Crea una
Observa cómo EmailNotification reemplaza completamente el comportamiento del padre, mientras que PushNotification lo extiende llamando primero a super.send(). Ambos enfoques son formas válidas de sobrescribir métodos dependiendo de tus necesidades.
Salida esperada:
Notification: Alert - System update available
Sending email to user@example.com: Welcome - Thanks for signing up!
Notification: Reminder - Meeting in 10 minutes
Pushed to device: DEVICE-001Hoja de referencia
La sobrescritura de métodos ocurre cuando una clase hija proporciona su propia implementación de un método que ya existe en la clase padre. La versión de la hija reemplaza a la del padre cuando se llama en instancias de la hija.
Para sobrescribir un método, defínalo en la clase hija con el mismo nombre y parámetros:
class Animal {
String name;
Animal(this.name);
void speak() {
print('$name makes a sound');
}
}
class Dog extends Animal {
Dog(String name) : super(name);
void speak() {
print('$name barks: Woof!');
}
}
void main() {
var animal = Animal('Generic');
var dog = Dog('Buddy');
animal.speak(); // Generic hace un sonido
dog.speak(); // Buddy ladra: ¡Guau!
}Puede usar super para llamar a la versión del padre y extender el comportamiento en lugar de reemplazarlo:
class Cat extends Animal {
Cat(String name) : super(name);
void speak() {
super.speak(); // Llamar primero a la versión del padre
print('$name also purrs');
}
}Pruébalo tú mismo
import 'notification.dart';
void main() {
// TODO: Crea una Notification base con title 'Alert' y message 'System update available'
// Llama a su método send()
// TODO: Imprime una línea vacía
// TODO: Crea una EmailNotification con:
// - title: 'Welcome'
// - message: 'Thanks for signing up!'
// - recipient: 'user@example.com'
// Llama a su método send()
// TODO: Imprime una línea vacía
// TODO: Crea una PushNotification con:
// - title: 'Reminder'
// - message: 'Meeting in 10 minutes'
// - deviceId: 'DEVICE-001'
// Llama a su método send()
}
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
1Fundamentos de POO
Archivos externosLibrerías e importacionesIntroducción a la POOClases vs. ObjetosLa palabra clave thisMétodosVariables de instanciaConceptos básicos de constructoresResumen - Calculadora sencilla4Seguridad de nulos
Introducción a la seguridad de nulosNulables vs No nulablesLos operadores ? y !Palabra clave Late y Null SafetyOperadores Null-awareNull Safety en clasesResumen - Sistema de perfil de usuario7Clases abstractas e interfaces
Clases abstractasMétodos abstractosInterfaces en DartInterfaces implícitasImplementar vs. ExtenderInterfaces múltiplesRepaso - Calculadora de figuras10Colecciones y Genéricos
Visión general de List, Set y MapColecciones con seguridad de tiposClases genéricasMétodos genéricosRestricciones genéricasIterable e IteratorResumen - Almacenamiento genérico2Constructores en Dart
Constructor por defectoConstructores nombradosListas de inicializaciónConstructores constantesConstructores de fábricaConstructores de redireccionamientoResumen - Constructor de formas5Encapsulamiento
Miembros públicos vs. privadosLa convención del prefijo _Privacidad a nivel de libreríaProfundidad en Getters y SettersOcultamiento de informaciónResumen - Registros de estudiantes8Mixins
Introducción a los MixinsCreación de MixinsUso de múltiples MixinsPalabra clave on en MixinsMixin vs HerenciaMixin vs InterfazResumen - Sistema Animal11Métodos especiales
Sobrescritura de toString()Sobrescritura de hashCode y ==Interfaz ComparableMétodo call()Sobrescritura de noSuchMethodResumen - Colección personalizada14Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy3Propiedades de clase
Miembros de instancia vs. estáticosCampos Final y ConstVariables LateMétodos y campos estáticosGetters y SettersResumen - Gestor de cuentas bancarias6Herencia
Herencia básicaLa palabra clave superSobrescritura de métodosLa anotación @overrideLa palabra clave final en clasesConstructores y herenciaResumen - Jerarquía de empleados9Polimorfismo
Fundamentos del polimorfismoPolimorfismo mediante interfacesComprobación de tipos en tiempo de ejecuciónLos operadores is y asPalabra clave covariantResumen - Procesador de pagos12POO Asíncrona
Futures y async/awaitFundamentos de StreamsStream ControllersConstructores asíncronosAsincronía en métodos de claseRepaso - Data Fetcher15Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository