Interfacce implicite
Fa parte della sezione Programmazione orientata agli oggetti del percorso Dart di Coddy. Lezione 46 di 110.
Poiché ogni classe Dart definisce automaticamente un'interfaccia, puoi usare qualsiasi classe come interfaccia, anche le classi concrete con implementazioni complete. Questo è ciò che chiamiamo interfaccia implicita.
Considera una classe con proprietà e metodi:
class Logger {
String prefix = '[LOG]';
void log(String message) {
print('$prefix $message');
}
void clear() {
print('Clearing logs...');
}
}Quando un'altra classe implementa Logger, deve fornire la propria implementazione per tutto, inclusa la proprietà prefix:
class FileLogger implements Logger {
@override
String prefix = '[FILE]';
@override
void log(String message) {
print('$prefix Writing to file: $message');
}
@override
void clear() {
print('Deleting log file...');
}
}Questa è l’intuizione fondamentale: quando usi implements, stai dicendo «la mia classe avrà la stessa struttura», ovvero gli stessi metodi e proprietà. Non erediti alcun codice, costruttore o valore predefinito. Ti impegni soltanto a rispettare la struttura dell’interfaccia.
Questo rende le interfacce implicite potenti per creare componenti intercambiabili. Il codice che si aspetta un Logger può funzionare con qualsiasi classe che implementi la sua interfaccia, indipendentemente da come funziona internamente quell’implementazione.
Sfida
FacileCostruiamo un sistema di notifiche che dimostri come le classi concrete possano fungere da interfacce implicite. Creerai una classe di base per le notifiche e poi la implementerai in modo completamente diverso, mostrando che implements richiede di fornire personalmente tutti i membri.
Organizzerai il codice in due file:
notification.dart: definisci qui le tue classi di notifica:- Una classe
Notificationcon una proprietàString channelimpostata su'default', un metodosend(String message)che stampa[channel]: [message]e un metodogetStatus()che restituisce la stringa'Notification ready' - Una classe
EmailNotificationche implementaNotification. Poiché usiimplements, devi fornire una tua proprietàchannel(impostala su'email'), un tuo metodosend()che stampaSending email: [message]e un tuo metodogetStatus()che restituisce'Email service active' - Una classe
PushNotificationche implementaNotification. Imposta il suochannelsu'push', fai in modo chesend()stampiPush alert: [message]e fai restituire agetStatus()'Push service connected'
- Una classe
main.dart: importa il file delle notifiche e mostra come classi diverse possano implementare la stessa interfaccia implicita con comportamenti completamente diversi:- Crea un'istanza di
EmailNotificatione una diPushNotification - Per ogni notifica, stampa il suo stato usando
getStatus(), poi chiamasend()con il messaggio'Hello World' - Stampa una riga vuota tra le due notifiche
- Crea un'istanza di
Ricorda: quando usi implements, non erediti alcun codice da Notification. Prometti solo che la tua classe avrà la stessa struttura: le stesse proprietà e gli stessi metodi. Ogni classe che implementa l'interfaccia fornisce la propria implementazione completa.
Output previsto:
Email service active
Sending email: Hello World
Push service connected
Push alert: Hello WorldProvalo tu
import 'notification.dart';
void main() {
// TODO: Crea un'istanza di EmailNotification
// TODO: Stampa lo stato della notifica email usando getStatus()
// TODO: Invia un messaggio 'Hello World' usando la notifica email
// TODO: Stampa una riga vuota
// TODO: Crea un'istanza di PushNotification
// TODO: Stampa lo stato della notifica push usando getStatus()
// TODO: Invia un messaggio 'Hello World' usando la notifica push
}
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