interface în Dart

Modificator de clasă (Dart 3): în afara fișierului ei, clasa poate fi doar implementată, nu și extinsă.

Sintaxă
interface class Nume { ... }            // se poate implementa, nu și extinde (în alt fișier)
abstract interface class Nume { ... }   // interfață pură: doar implements

Ce face interface

Modificatorul interface spune: „alte biblioteci pot implementa această clasă (implements), dar nu o pot extinde (extends)”. Așa autorul clasei poate schimba codul metodelor ei fără să strice subclase scrise de alții, pentru că astfel de subclase nu există.

Cel mai des apare ca abstract interface class: o interfață pură, care nu se poate instanția și nu se poate extinde, doar implementa. Este echivalentul unei interfețe din Java sau C#.

Restricțiile modificatorilor de clasă (interface, base, final, sealed) se aplică doar în afara bibliotecii (fișierului) unde este declarată clasa. În același fișier poți face orice; de aceea exemplul cu eroarea are două fișiere.

Exemple

Exemplul 1: Interfață pură pentru un depozit de date

Depozit descrie doar operațiile; DepozitMemorie le implementează.

abstract interface class Depozit {
  void salveaza(String cheie, String valoare);
  String? citeste(String cheie);
}

class DepozitMemorie implements Depozit {
  final _date = <String, String>{};

  @override
  void salveaza(String cheie, String valoare) => _date[cheie] = valoare;

  @override
  String? citeste(String cheie) => _date[cheie];
}

void main() {
  final Depozit d = DepozitMemorie();
  d.salveaza('oras', 'Timișoara');
  print(d.citeste('oras'));
  print(d.citeste('judet') ?? 'nu există');
}

Rezultat

Timișoara
nu există

Exemplul 2: interface class poate fi și instanțiată

Fără abstract, clasa are cod propriu și se poate crea direct.

interface class Salut {
  String mesaj(String nume) => 'Bună, $nume!';
}

class SalutFormal implements Salut {
  @override
  String mesaj(String nume) => 'Bună ziua, domnule $nume.';
}

void main() {
  print(Salut().mesaj('Ana'));
  print(SalutFormal().mesaj('Popescu'));
}

Rezultat

Bună, Ana!
Bună ziua, domnule Popescu.

Exemplul 3: Extinderea dintr-un alt fișier este interzisă

vehicule.dart declară interface class Vehicul. În main.dart, implements este permis, dar extends dă eroare.

// vehicule.dart
interface class Vehicul {
  void porneste() => print('Vehiculul pornește.');
}

// main.dart
import 'vehicule.dart';

class Masina extends Vehicul {}            // interzis

class Bicicleta implements Vehicul {       // permis
  @override
  void porneste() => print('Pedalez.');
}

Rezultatul lui dart analyze (al doilea fișier nu se compilează)

  error - main.dart:3:22 - The class 'Vehicul' can't be extended outside of its library because it's an interface class. - invalid_use_of_type_outside_library

Greșeli frecvente

  • Să aștepți eroarea în același fișier: modificatorii de clasă nu au efect în biblioteca unde a fost declarată clasa.
  • Să confunzi interface class cu abstract interface class: prima se poate instanția, a doua nu.
  • Să crezi că Dart are nevoie de interface pentru implements: orice clasă (care nu e base/final/sealed) poate fi implementată.

Comenzi înrudite

  • implements: O clasă promite că are toți membrii altor clase (interfețe) și îi scrie singură, fără să moștenească codul lor.
  • abstract: O clasă abstractă nu poate fi instanțiată direct; definește ce trebuie să facă subclasele ei.
  • base: Modificator de clasă (Dart 3): clasa poate fi extinsă, dar nu implementată în afara fișierului ei.
  • final class: Modificator de clasă (Dart 3): clasa nu poate fi extinsă și nici implementată în afara fișierului ei.
  • sealed: Clasă cu un set închis de subtipuri, toate în același fișier; switch-ul pe ea verifică dacă ai tratat toate cazurile.