implements în Dart

O clasă promite că are toți membrii altor clase (interfețe) și îi scrie singură, fără să moștenească codul lor.

Sintaxă
class Nume implements Interfata1, Interfata2 {
  @override
  Tip metoda() { ... }   // trebuie implementați TOȚI membrii
}

Ce face implements

În Dart orice clasă definește implicit și o interfață: lista membrilor ei publici. class Cerc implements Forma spune că Cerc poate fi folosit ca Forma, dar, spre deosebire de extends, nu primește nimic: trebuie să scrie el toate metodele, getter-ele și câmpurile lui Forma.

O clasă poate implementa mai multe interfețe deodată (implements Comparable<Nota>, Exportabil) și poate în același timp să extindă o clasă. De obicei interfețele sunt clase abstract sau abstract interface.

implements este util pentru a înlocui o componentă cu alta (de exemplu o bază de date reală cu una de test) fără să schimbi codul care o folosește.

Exemple

Exemplul 1: Două implementări ale aceleiași interfețe

Funcția trimite nu știe dacă primește e-mail sau SMS; știe doar că poate apela notifica. SMS-ul scurtează mesajul la primele 20 de caractere.

abstract class Notificator {
  void notifica(String destinatar, String mesaj);
}

class Email implements Notificator {
  @override
  void notifica(String destinatar, String mesaj) =>
      print('E-mail către $destinatar: $mesaj');
}

class Sms implements Notificator {
  @override
  void notifica(String destinatar, String mesaj) =>
      print('SMS către $destinatar: ${mesaj.substring(0, 20)}...');
}

void trimite(Notificator n) => n.notifica('Ana', 'Comanda ta a fost livrată în Cluj.');

void main() {
  trimite(Email());
  trimite(Sms());
}

Rezultat

E-mail către Ana: Comanda ta a fost livrată în Cluj.
SMS către Ana: Comanda ta a fost li...

Exemplul 2: Mai multe interfețe deodată

Nota implementează Comparable (pentru sortare) și o interfață proprie.

abstract class Exportabil {
  String inCsv();
}

class Nota implements Comparable<Nota>, Exportabil {
  final String elev;
  final int valoare;
  Nota(this.elev, this.valoare);

  @override
  int compareTo(Nota alta) => alta.valoare.compareTo(valoare);

  @override
  String inCsv() => '$elev;$valoare';
}

void main() {
  final note = [Nota('Ana', 8), Nota('Bogdan', 10), Nota('Carla', 9)]..sort();
  for (final n in note) {
    print(n.inCsv());
  }
}

Rezultat

Bogdan;10
Carla;9
Ana;8

Exemplul 3: Implementarea unei clase obișnuite pentru teste

MeteoFals implementează interfața lui Meteo și înlocuiește serviciul real, fără să moștenească nimic din el.

class Meteo {
  double temperatura(String oras) {
    throw UnimplementedError('aici s-ar face o cerere pe internet');
  }
}

class MeteoFals implements Meteo {
  @override
  double temperatura(String oras) => {'Iași': 18.5, 'Constanța': 24.0}[oras] ?? 20;
}

String sfat(Meteo m, String oras) =>
    m.temperatura(oras) > 22 ? '$oras: ia ochelari de soare' : '$oras: ia o geacă';

void main() {
  final meteo = MeteoFals();
  print(sfat(meteo, 'Iași'));
  print(sfat(meteo, 'Constanța'));
}

Rezultat

Iași: ia o geacă
Constanța: ia ochelari de soare

Greșeli frecvente

  • Să crezi că implements moștenește codul: trebuie să scrii fiecare membru, altfel apare Missing concrete implementation of ....
  • Uitarea câmpurilor: un câmp public al interfeței trebuie implementat și el (ca un câmp sau ca getter/setter).
  • Să implementezi o clasă base sau final din alt fișier: modificatorii de clasă interzic asta.

Comenzi înrudite

  • extends: Creează o subclasă care moștenește câmpurile și metodele altei clase și le poate înlocui.
  • abstract: O clasă abstractă nu poate fi instanțiată direct; definește ce trebuie să facă subclasele ei.
  • interface: Modificator de clasă (Dart 3): în afara fișierului ei, clasa poate fi doar implementată, nu și extinsă.
  • mixin și with: Un mixin este un pachet de metode și câmpuri pe care îl adaugi în mai multe clase cu with, fără moștenire.