Implementare vs estendere
Fa parte della sezione Programmazione orientata agli oggetti del percorso Dart di Coddy. Lezione 47 di 110.
Ora che hai compreso sia extends sia implements, chiariamo quando usare ciascuno dei due.
Usa extends quando vuoi ereditare un comportamento. La tua sottoclasse ottiene gratuitamente tutto il codice della classe genitore e può basarsi su di esso:
class Animal {
void breathe() {
print('Breathing...');
}
}
class Dog extends Animal {
void bark() {
print('Woof!');
}
}
void main() {
var dog = Dog();
dog.breathe(); // Ereditato - funziona automaticamente
dog.bark();
}Usa implements quando vuoi garantire una struttura senza ereditare codice. Devi scrivere ogni metodo tu stesso:
class Robot implements Animal {
@override
void breathe() {
print('Ventilating circuits...'); // Implementazione completamente personalizzata
}
}La differenza fondamentale: extends dice «Sono un tipo di questo», mentre implements dice «Posso fare ciò che fa questo». Un Dog è un Animal e respira allo stesso modo. Un Robot non è un animale, ma può rispettare lo stesso contratto con la propria logica.
Ricorda: puoi estendere una sola classe, ma puoi implementare molte interfacce. Scegli extends per le vere relazioni di ereditarietà e implements quando hai bisogno di flessibilità o vuoi imporre un contratto senza condividere i dettagli dell'implementazione.
Sfida
FacileCostruiamo un sistema di lavoratori che mostri quando usare extends invece di implements. Creerai una classe base Worker e mostrerai poi entrambi gli approcci: una classe che davvero "is a" worker ed eredita il comportamento, e un'altra che semplicemente "can do" ciò che fa un lavoratore, ma con una logica completamente personalizzata.
Organizzerai il codice in due file:
worker.dart: definisci qui la gerarchia dei lavoratori:- Una classe
Workercon una proprietàString namee un costruttore. Includi un metodowork()che stampa[name] is working...e un metodotakeBreak()che stampa[name] takes a coffee break - Una classe
OfficeWorkerche estendeWorker. Aggiungi una proprietàString department. Sovrascriviwork()per stampare[name] is typing reports in [department], mantenendo però il comportamento ereditato ditakeBreak() - Una classe
RobotWorkerche implementaWorker. Aggiungi una proprietàString model. Poiché i robot non sono davvero lavoratori, ma possono fare ciò che fanno i lavoratori, fornisci implementazioni completamente personalizzate:work()dovrebbe stampareRobot [model] is assembling partsetakeBreak()dovrebbe stampareRobot [model] is recharging
- Una classe
main.dart: importa il file dei lavoratori e mostra entrambi gli approcci:- Crea un
OfficeWorkerchiamato'Alice'nel reparto'Marketing' - Crea un
RobotWorkercon il modello'RX-7' - Per il lavoratore dell'ufficio, chiama
work()e poitakeBreak() - Stampa una riga vuota
- Per il lavoratore robot, chiama
work()e poitakeBreak()
- Crea un
Nota come OfficeWorker eredita automaticamente takeBreak() perché estende Worker: è davvero "is a" worker. Nel frattempo, RobotWorker deve fornire una propria implementazione per tutto perché implementa soltanto l'interfaccia: "can do" ciò che fa un lavoratore, ma a modo suo, da robot.
Output previsto:
Alice is typing reports in Marketing
Alice takes a coffee break
Robot RX-7 is assembling parts
Robot RX-7 is rechargingProvalo tu
import 'worker.dart';
void main() {
// TODO: Crea un OfficeWorker di nome 'Alice' nel reparto 'Marketing'
// TODO: Crea un RobotWorker con modello 'RX-7'
// TODO: Per l'impiegato d'ufficio, chiama work() e poi takeBreak()
// TODO: Stampa una riga vuota
// TODO: Per il lavoratore robot, chiama work() e poi takeBreak()
}
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