Fondamenti di polimorfismo
Fa parte della sezione Programmazione orientata agli oggetti del percorso Dart di Coddy. Lezione 57 di 110.
Il polimorfismo significa «molte forme»: è la capacità di trattare oggetti di classi diverse tramite un'interfaccia comune. Quando hai un riferimento a una classe genitore, può puntare a un oggetto di qualsiasi classe figlia e viene chiamato il metodo corretto in base al tipo effettivo dell'oggetto.
Questo è potente perché puoi scrivere codice che funziona con il tipo genitore, ma gestisce automaticamente correttamente tutti i tipi figli:
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 genitore, oggetto figlio
myPet.speak(); // Output: Woof!
myPet = Cat(); // Stessa variabile, oggetto diverso
myPet.speak(); // Output: Meow!
}La variabile myPet è dichiarata come Animal, ma contiene un Dog o un Cat. Quando viene chiamato speak(), Dart verifica il tipo effettivo dell'oggetto in fase di esecuzione e chiama il metodo sovrascritto appropriato.
Questo ti permette di scrivere funzioni flessibili che funzionano con qualsiasi sottoclasse:
void makeAllSpeak(List<Animal> animals) {
for (var animal in animals) {
animal.speak(); // Ogni animale si esprime a modo suo
}
}
void main() {
var pets = [Dog(), Cat(), Dog()];
makeAllSpeak(pets);
// Output: Woof! Meow! Woof!
}La funzione non deve conoscere Dog o Cat: funziona semplicemente con Animal. Questo rende il tuo codice più estensibile, poiché aggiungere nuovi tipi di animali non richiede modifiche alle funzioni esistenti.
Sfida
FacileCostruiamo un sistema di strumenti musicali che mostri il polimorfismo in azione. Creerai una classe base Instrument e diversi tipi di strumenti, poi scriverai una funzione che può far suonare insieme qualsiasi gruppo di strumenti, senza conoscerne i tipi specifici.
Organizzerai il codice in due file:
instruments.dart: definisci qui la gerarchia degli strumenti:- Una classe
Instrumentcon una proprietàString namee un costruttore. Includi un metodoplay()che stampa[name] makes a sound - Una classe
Guitarche estendeInstrumente sovrascriveplay()per stampare[name] strums melodically - Una classe
Drumche estendeInstrumente sovrascriveplay()per stampare[name] beats rhythmically - Una classe
Pianoche estendeInstrumente sovrascriveplay()per stampare[name] plays harmoniously
performConcert(List<Instrument> instruments)che stampaConcert begins!, poi scorre l'elenco chiamandoplay()su ogni strumento e infine stampaConcert ends!- Una classe
main.dart: importa il file degli strumenti e mostra il polimorfismo creando una band composta da strumenti diversi:- Crea un elenco di tipo
List<Instrument>contenente unaGuitarchiamata'Acoustic', unDrumchiamato'Snare'e unPianochiamato'Grand' - Passa questo elenco a
performConcert()
- Crea un elenco di tipo
Nota come performConcert() utilizzi il tipo genitore Instrument, eppure ogni strumento suoni a modo suo. Questo è il polimorfismo: la stessa chiamata di metodo produce comportamenti diversi in base al tipo effettivo dell'oggetto.
Output previsto:
Concert begins!
Acoustic strums melodically
Snare beats rhythmically
Grand plays harmoniously
Concert ends!Provalo tu
import 'instruments.dart';
void main() {
// TODO: Crea una List<Instrument> che contenga:
// - Una Guitar chiamata 'Acoustic'
// - Un Drum chiamato 'Snare'
// - Un Piano chiamato 'Grand'
// TODO: Chiama performConcert() con la tua lista di strumenti
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniLibrerie e importazioniIntroduzione alla programmazione orientata agli oggettiClassi e oggettiLa parola chiave thisMetodiVariabili di istanzaFondamenti dei costruttoriRiepilogo - Calcolatrice semplice4Sicurezza dei valori null
Introduzione alla sicurezza dei valori nullNullable e non nullableGli operatori ? e !La keyword late e la sicurezza dei valori nullOperatori null-awareSicurezza dei valori null nelle classiRiepilogo - Sistema di profili utente7Classi astratte e interfacce
Classi astratteMetodi astrattiInterfacce in DartInterfacce impliciteImplementare vs estendereInterfacce multipleRiepilogo - Calcolatore di forme10Collezioni e generici
Panoramica di List, Set e MapCollezioni sicure rispetto ai tipiClassi genericheMetodi genericiVincoli sui genericiIterable e IteratorRiepilogo - Archiviazione generica13Concetti avanzati di OOP
Composizione vs ereditarietàMetodi di estensioneClassi chiamabiliClassi sealed (Dart 3)Record (Dart 3)Pattern e matching (3.0)Enum con metodi16Progetto: Gestione della biblioteca
Panoramica del progettoClassi Libro e Utente2I costruttori in Dart
Costruttore predefinitoCostruttori con nomeListe di inizializzazioneCostruttori costantiCostruttori factoryCostruttori di reindirizzamentoRiepilogo - Crea forme5Incapsulamento
Membri pubblici e privatiConvenzione del prefisso _Visibilità a livello di libreriaApprofondimento su getter e setterNascondimento delle informazioniRiepilogo - Registri degli studenti8Mixin
Introduzione ai MixinCreare MixinUsare più MixinParola chiave on nei MixinMixin vs ereditarietàMixin vs interfacciaRiepilogo - Sistema animale11Metodi speciali
Sovrascrittura di toString()Sovrascrittura di hashCode e ==Interfaccia ComparableMetodo call()Sovrascrittura di noSuchMethodRiepilogo - Collezione personalizzata14Modelli di progettazione Parte 1
Introduzione ai modelli di progettazioneSingletonFactoryObserverStrategy3Proprietà delle classi
Membri di istanza e staticiCampi final e constVariabili lateMetodi e campi staticiGetter e setterRiepilogo - Gestore di conti bancari6Ereditarietà
Ereditarietà di baseLa parola chiave superOverride dei metodiL’annotazione @overrideLa parola chiave final per le classiCostruttori ed ereditarietàRiepilogo - Gerarchia dei dipendenti9Polimorfismo
Fondamenti di polimorfismoPolimorfismo tramite interfacceControllo del tipo a runtimeGli operatori is e asParola chiave covariantRiepilogo - Elaboratore di pagamenti12OOP asincrona
Future e async/awaitNozioni di base sugli streamController degli streamCostruttori asincroniAsync nei metodi di classeRiepilogo - Recupero dei dati15Pattern di progettazione Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositePattern RepositoryEsercitati da solo: Compilatore Dart online