Mixin vs ereditarietà
Fa parte della sezione Programmazione orientata agli oggetti del percorso Dart di Coddy. Lezione 54 di 110.
Ora che hai imparato come funzionano i mixin, chiariamo quando usarli invece dell'ereditarietà. La differenza principale sta nella relazione che esprimono.
L'ereditarietà rappresenta una relazione "è-un". Un Dog è un Animal. La sottoclasse è una versione specializzata della classe genitore e puoi estendere una sola classe.
I mixin, d'altra parte, rappresentano una relazione di tipo "può fare". Un Dog può nuotare, ma nuotare non è ciò che definisce un cane.
// Ereditarietà: Dog È un Animal
class Animal {
String name;
Animal(this.name);
}
class Dog extends Animal {
Dog(String name) : super(name);
}
// Mixin: Dog PUÒ nuotare (ma non è definito dal fatto di nuotare)
mixin Swimming {
void swim() => print('Swimming');
}
class Dog extends Animal with Swimming {
Dog(String name) : super(name);
}Usa l'ereditarietà quando le classi condividono un'identità fondamentale e hai bisogno di costruttori nella classe genitore. Usa i mixin quando vuoi aggiungere funzionalità a classi che non condividono un antenato comune.
| Caratteristica | Ereditarietà | Mixin |
|---|---|---|
| Relazione | è-un | può-fare |
| Limite | Un solo genitore | Più mixin |
| Costruttori | Consentiti | Non consentiti |
| Caso d'uso | Specializzazione | Comportamento condiviso |
La parte migliore? Puoi combinarli entrambi: estendere una classe e integrare più funzionalità, dando alle tue classi esattamente le caratteristiche di cui hanno bisogno.
Sfida
FacileCostruiamo un sistema di lavoratori che mostri quando usare l'ereditarietà invece dei mixin. Creerai una classe base per la relazione «è-un» e dei mixin per le capacità «può-fare», poi li combinerai per mostrare come funzionano insieme entrambi gli approcci.
Organizzerai il codice in tre file:
worker.dart: Definisci la classe base che stabilisce l'identità fondamentale di tutti i lavoratori:- Una classe
Workercon le proprietàString nameeString department. Includi un costruttore che accetta entrambi i valori. Aggiungi un metodointroduce()che stampa[name] works in [department]
- Una classe
skills.dart: Definisci i mixin che rappresentano le capacità che i lavoratori possono avere (le relazioni «può-fare»):- Un mixin
CanCodecon un metodowriteCode()che stampaWriting code... - Un mixin
CanDesigncon un metodocreateDesign()che stampaCreating design... - Un mixin
CanManagecon un metodoleadTeam()che stampaLeading the team...
- Un mixin
main.dart: Importa entrambi i file e crea tipi specializzati di lavoratori che combinano l'ereditarietà con i mixin:- Una classe
Developerche estendeWorkere usa il mixinCanCode - Una classe
TechLeadche estendeWorkere usa entrambi i mixinCanCodeeCanManage - Crea un
Developerdi nome'Alice'nel reparto'Engineering' - Crea un
TechLeaddi nome'Bob'nel reparto'Engineering' - Per Alice: chiama
introduce()e poiwriteCode() - Stampa una riga vuota
- Per Bob: chiama
introduce(), poiwriteCode()e infineleadTeam()
- Una classe
Nota come sia Developer sia TechLead siano lavoratori (ereditarietà), ma possano fare cose diverse (mixin). TechLead combina più capacità senza bisogno dell'ereditarietà multipla.
Output previsto:
Alice works in Engineering
Writing code...
Bob works in Engineering
Writing code...
Leading the team...Provalo tu
import 'worker.dart';
import 'skills.dart';
// TODO: Crea una classe Developer che estenda Worker e usi il mixin CanCode
// TODO: Crea una classe TechLead che estenda Worker e usi entrambi i mixin CanCode e CanManage
void main() {
// TODO: Crea un Developer di nome 'Alice' nel dipartimento 'Engineering'
// TODO: Chiama introduce() e poi writeCode() per Alice
// TODO: Stampa una riga vuota
// TODO: Crea un TechLead di nome 'Bob' nel dipartimento 'Engineering'
// TODO: Chiama introduce(), poi writeCode() e infine leadTeam() per Bob
}
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