Sobrescrita de Método
Parte da seção Programação Orientada a Objetos do Journey de Dart da Coddy — lição 38 de 110.
Sobrescrita de método (method overriding) ocorre quando uma classe filha fornece sua própria implementação de um método que já existe na classe pai. Isso permite que as subclasses personalizem o comportamento herdado, mantendo a mesma assinatura do método.
Quando você define um método em uma classe filha com o mesmo nome e parâmetros de um na classe pai, a versão da filha assume o controle:
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 faz um som
dog.speak(); // Buddy late: Woof!
}Quando você chama speak() em uma instância de Dog, o Dart executa a versão do Dog, não a do Animal. A classe filha sobrescreveu o método da classe pai.
Você também pode combinar a sobrescrita com super para estender em vez de substituir o comportamento do pai:
class Cat extends Animal {
Cat(String name) : super(name);
void speak() {
super.speak(); // Chama a versão do pai primeiro
print('$name also purrs');
}
}Este padrão permite que você construa sobre funcionalidades existentes. A regra principal é simples: o mesmo nome de método e parâmetros na classe filha substitui a implementação da classe pai quando chamado em instâncias da filha.
Desafio
FácilVamos construir um sistema de notificação que demonstra como as classes filhas podem sobrescrever métodos dos pais para personalizar o comportamento. Você criará diferentes tipos de notificação, cada um entregando mensagens de sua própria maneira única.
Você organizará seu código em dois arquivos:
notification.dart: Defina sua hierarquia de notificação aqui:- Uma classe
Notification(a classe pai) com umaString titleeString message. Inclua um construtor que receba ambos os valores e um métodosend()que imprimaNotification: [title] - [message] - Uma classe
EmailNotificationque estendeNotificatione adiciona uma propriedadeString recipient. Sobrescreva o métodosend()para imprimirSending email to [recipient]: [title] - [message] - Uma classe
PushNotificationque estendeNotificatione adiciona uma propriedadeString deviceId. Sobrescreva o métodosend()para primeiro chamar osend()do pai usandosuper, e depois imprimirPushed to device: [deviceId]na linha seguinte
- Uma classe
main.dart: Importe seu arquivo de notificação e demonstre a sobrescrita de métodos em ação:- Crie uma
Notificationbase com o título'Alert'e a mensagem'System update available' - Chame seu método
send() - Imprima uma linha vazia
- Crie uma
EmailNotificationcom o título'Welcome', mensagem'Thanks for signing up!'e destinatário'user@example.com' - Chame seu método
send() - Imprima uma linha vazia
- Crie uma
PushNotificationcom o título'Reminder', mensagem'Meeting in 10 minutes'e deviceId'DEVICE-001' - Chame seu método
send()
- Crie uma
Observe como EmailNotification substitui completamente o comportamento do pai, enquanto PushNotification o estende chamando super.send() primeiro. Ambas as abordagens são formas válidas de sobrescrever métodos, dependendo das suas necessidades.
Saída 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-001Folha de consulta
A sobrescrita de método (method overriding) ocorre quando uma classe filha fornece sua própria implementação de um método que já existe na classe pai. A versão da classe filha substitui a da classe pai quando chamada em instâncias da filha.
Para sobrescrever um método, defina-o na classe filha com o mesmo nome e 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 makes a sound
dog.speak(); // Buddy barks: Woof!
}Você pode usar super para chamar a versão da classe pai e estender em vez de substituir o comportamento:
class Cat extends Animal {
Cat(String name) : super(name);
void speak() {
super.speak(); // Chama a versão da classe pai primeiro
print('$name also purrs');
}
}Experimente você mesmo
import 'notification.dart';
void main() {
// TODO: Crie uma Notification base com title 'Alert' e message 'System update available'
// Chame seu método send()
// TODO: Imprima uma linha vazia
// TODO: Crie uma EmailNotification com:
// - title: 'Welcome'
// - message: 'Thanks for signing up!'
// - recipient: 'user@example.com'
// Chame seu método send()
// TODO: Imprima uma linha vazia
// TODO: Crie uma PushNotification com:
// - title: 'Reminder'
// - message: 'Meeting in 10 minutes'
// - deviceId: 'DEVICE-001'
// Chame seu método send()
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos ExternosBibliotecas e ImportaçõesIntrodução à POOClasses vs ObjetosA Palavra-chave thisMétodosVariáveis de InstânciaFundamentos de ConstrutoresRecapitulação - Calculadora Simples4Null Safety
Introdução ao Null SafetyNullable vs Non-NullableOs Operadores ? e !Palavra-chave Late e Null SafetyOperadores Null-AwareNull Safety em ClassesRecapitulação - Sistema de Perfil de Usuário7Classes Abstratas e Interfaces
Classes AbstratasMétodos AbstratosInterfaces em DartInterfaces ImplícitasImplementando vs EstendendoMúltiplas InterfacesRecapitulação - Calculadora de Formas10Coleções e Generics
Visão Geral de List, Set e MapColeções Type-SafeClasses GenéricasMétodos GenéricosRestrições de GenericsIterable e IteratorRecapitulação - Armazenamento Genérico13Conceitos Avançados de POO
Composição vs HerançaMétodos de ExtensãoClasses ChamáveisClasses Seladas (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums com Métodos16Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses Livro e Usuário2Construtores em Dart
Construtor PadrãoConstrutores NomeadosListas de InicializaçãoConstrutores ConstantesConstrutores FactoryConstrutores de RedirecionamentoRecapitulação - Shape Builder5Encapsulamento
Membros Públicos vs PrivadosA Convenção do Prefixo _Privacidade em Nível de BibliotecaAprofundamento em Getters & SettersOcultação de InformaçãoRecapitulação - Registros de Estudantes8Mixins
Introdução aos MixinsCriando MixinsUsando Múltiplos MixinsPalavra-chave on em MixinsMixin vs HerançaMixin vs InterfaceRecapitulação - Sistema Animal11Métodos Especiais
Sobrescrita de toString()Sobrescrita de hashCode & ==Interface ComparableMétodo call()Sobrescrita de noSuchMethodRecapitulação - Coleção Personalizada14Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão Strategy3Propriedades de Classe
Membros de Instância vs EstáticosCampos Final & ConstVariáveis LateMétodos e Campos EstáticosGetters e SettersRecapitulação - Gerenciador de Conta Bancária6Herança
Herança BásicaA Palavra-chave superSobrescrita de MétodoA Anotação @overrideA Palavra-chave final para ClassesConstrutores e HerançaRecapitulação - Hierarquia de Funcionários9Polimorfismo
Fundamentos do PolimorfismoPolimorfismo via InterfacesVerificação de Tipos em Tempo de ExecuçãoOs Operadores is & asPalavra-chave CovariantRecapitulação - Processador de Pagamentos12POO Assíncrona
Futures e async/awaitFundamentos de StreamsStream ControllersConstrutores AssíncronosAsync em Métodos de ClasseRecapitulação - Data Fetcher15Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Repository