Menu
Coddy logo textTech

Mixin vs interfaccia

Fa parte della sezione Programmazione orientata agli oggetti del percorso Dart di Coddy. Lezione 55 di 110.

Hai visto come i mixin si confrontano con l'ereditarietà. Ora confrontiamo i mixin con le interfacce, poiché entrambi ti permettono di lavorare con più tipi. La differenza principale è ciò che forniscono: le interfacce definiscono un contratto, mentre i mixin forniscono un'implementazione.

Quando implementi un'interfaccia, prometti di fornire determinati metodi, ma scrivi tutto il codice da solo. Quando usi un mixin, ottieni il codice effettivo gratuitamente.

// Approccio con interfaccia - devi implementare tutto
abstract class Printable {
  void printInfo();
}

class Report implements Printable {
  @override
  void printInfo() {
    print('Printing report...');  // Questo lo scrivi tu
  }
}

// Approccio con mixin - implementazione inclusa
mixin Printable {
  void printInfo() {
    print('Printing...');  // Già scritto per te
  }
}

class Report with Printable {}  // Ottiene printInfo() automaticamente

Quindi, quando dovresti usare ciascuno dei due? Usa un'interfaccia quando classi diverse hanno bisogno delle stesse firme dei metodi ma di implementazioni diverse. Usa un mixin quando le classi devono condividere esattamente lo stesso comportamento.

FunzionalitàInterfacciaMixin
FornisceSolo contrattoContratto + codice
ImplementazioneLa scrivi tuInclusa
Parola chiaveimplementswith
Ideale perComportamenti diversi, stessa APIComportamento condiviso

Puoi persino combinare entrambi gli approcci: usare le interfacce per definire cosa può fare una classe e i mixin per fornire implementazioni comuni, quando opportuno. In Dart, quando li combini, metti sempre with prima di implements:

class MyClass with SomeMixin implements SomeInterface {
  // with viene prima di implements
}
challenge icon

Sfida

Facile

Costruiamo un sistema di notifiche che mostri quando usare le interfacce anziché i mixin. Creerai un'interfaccia per le notifiche che richiedono implementazioni diverse e un mixin per il comportamento di registrazione condiviso, che dovrebbe essere identico per tutti i tipi di notifica.

Organizzerai il codice in tre file:

  • notifiable.dart: Definisci una classe astratta Notifiable che funge da interfaccia. Dovrebbe dichiarare due metodi astratti: send(String message) e getChannel(), che restituisce un String. I diversi tipi di notifica implementeranno questi metodi in modo diverso in base al proprio canale specifico.
  • logging.dart: Crea un mixin Logging che fornisce il comportamento condiviso che tutte le notifiche dovrebbero avere. Includi un metodo logSent(String channel, String message) che stampa [LOG] Sent via [channel]: [message] e un metodo logTimestamp() che stampa [LOG] Timestamp recorded. Questo comportamento è identico per tutti i tipi di notifica, quindi è perfetto per un mixin.
  • main.dart: Importa entrambi i file e crea due classi di notifica che combinano l'interfaccia con il mixin:
    • Una classe EmailNotification che usa il mixin Logging e implementa Notifiable. Il suo getChannel() dovrebbe restituire 'Email', mentre il suo metodo send() dovrebbe stampare Sending email: [message], poi chiamare logSent() con il canale e il messaggio, quindi chiamare logTimestamp()
    • Una classe SMSNotification che usa il mixin Logging e implementa Notifiable. Il suo getChannel() dovrebbe restituire 'SMS', mentre il suo metodo send() dovrebbe stampare Sending SMS: [message], poi chiamare logSent() con il canale e il messaggio, quindi chiamare logTimestamp()
    Poi crea un EmailNotification e chiama send('Hello World'), stampa una riga vuota, crea un SMSNotification e chiama send('Quick update')

Nota come l'interfaccia imponga a ciascuna classe di scrivere le proprie implementazioni di send() e getChannel() (comportamento diverso), mentre il mixin fornisce i metodi di registrazione che funzionano in modo identico per entrambe (comportamento condiviso).

Output previsto:

Sending email: Hello World
[LOG] Sent via Email: Hello World
[LOG] Timestamp recorded

Sending SMS: Quick update
[LOG] Sent via SMS: Quick update
[LOG] Timestamp recorded

Provalo tu

import 'notifiable.dart';
import 'logging.dart';

// TODO: Crea una classe EmailNotification che:
//       - usa il mixin Logging (with)
//       - implementa Notifiable (implements)
//       - getChannel() restituisce 'Email'
//       - send() stampa 'Sending email: [message]', poi chiama logSent() e infine logTimestamp()

// TODO: Crea una classe SMSNotification che:
//       - usa il mixin Logging (with)
//       - implementa Notifiable (implements)
//       - getChannel() restituisce 'SMS'
//       - send() stampa 'Sending SMS: [message]', poi chiama logSent() e infine logTimestamp()

void main() {
  // TODO: Crea un'istanza di EmailNotification e chiama send('Hello World')
  
  // TODO: Stampa una riga vuota
  
  // TODO: Crea un'istanza di SMSNotification e chiama send('Quick update')
}
quiz iconMettiti alla prova

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

Esercitati da solo: Compilatore Dart online