abstract în Dart

O clasă abstractă nu poate fi instanțiată direct; definește ce trebuie să facă subclasele ei.

Sintaxă
abstract class Nume {
  Tip metodaAbstracta();          // fără corp: subclasele o scriu
  Tip metodaConcreta() { ... }    // cu corp: se moștenește
}

Ce face abstract

abstract class Forma este un concept general, nu un obiect concret: nu poți scrie Forma(). Rolul ei este să fie extinsă sau implementată de clase concrete (Cerc, Patrat).

O metodă fără corp (doar semnătura, terminată cu ;) este abstractă. Orice subclasă concretă trebuie să o implementeze, altfel analizorul dă eroare. Clasa abstractă poate avea și metode cu corp, câmpuri și constructori, pe care subclasele le moștenesc.

Metodele abstracte pot exista doar în clase abstracte. Clasele abstracte sunt folosite des ca interfețe; pentru o interfață „pură”, fără cod, Dart 3 are și abstract interface class.

Exemple

Exemplul 1: O metodă abstractă și una concretă

arie este abstractă, fiecare formă o calculează altfel; descrie este moștenită de toate.

abstract class Forma {
  String get nume;
  double arie();

  void descrie() => print('$nume cu aria ${arie().toStringAsFixed(2)}');
}

class Cerc extends Forma {
  final double raza;
  Cerc(this.raza);
  @override
  String get nume => 'Cerc';
  @override
  double arie() => 3.14159 * raza * raza;
}

class Patrat extends Forma {
  final double latura;
  Patrat(this.latura);
  @override
  String get nume => 'Pătrat';
  @override
  double arie() => latura * latura;
}

void main() {
  final forme = <Forma>[Cerc(1.5), Patrat(4)];
  for (final f in forme) {
    f.descrie();
  }
}

Rezultat

Cerc cu aria 7.07
Pătrat cu aria 16.00

Exemplul 2: Șablon de algoritm

Clasa abstractă fixează pașii (genereaza), iar subclasele completează doar partea care diferă.

abstract class Raport {
  String titlu();
  List<String> randuri();

  void genereaza() {
    print('=== ${titlu()} ===');
    randuri().forEach(print);
    print('--- sfârșit ---');
  }
}

class RaportVanzari extends Raport {
  @override
  String titlu() => 'Vânzări octombrie';
  @override
  List<String> randuri() => ['Cluj: 12.400 lei', 'Iași: 9.850 lei'];
}

void main() {
  RaportVanzari().genereaza();
}

Rezultat

=== Vânzări octombrie ===
Cluj: 12.400 lei
Iași: 9.850 lei
--- sfârșit ---

Exemplul 3: Instanțierea unei clase abstracte

Analizorul oprește programul: o clasă abstractă nu se poate crea, iar o subclasă concretă trebuie să implementeze metoda abstractă.

abstract class Animal {
  void suna();
}

class Caine extends Animal {}

void main() {
  Animal();
}

Rezultatul lui dart analyze

  error - main.dart:5:7 - Missing concrete implementation of 'Animal.suna'. Try implementing the missing method, or make the class abstract. - non_abstract_class_inherits_abstract_member
  error - main.dart:8:3 - Abstract classes can't be instantiated. Try creating an instance of a concrete subtype. - instantiate_abstract_class

Greșeli frecvente

  • Forma() pentru o clasă abstractă: Abstract classes can't be instantiated. Creează o subclasă concretă sau folosește un constructor factory.
  • O metodă fără corp într-o clasă care nu este abstract: eroare.
  • Uitarea unei metode abstracte în subclasă: Missing concrete implementation.

Comenzi înrudite

  • extends: Creează o subclasă care moștenește câmpurile și metodele altei clase și le poate înlocui.
  • implements: O clasă promite că are toți membrii altor clase (interfețe) și îi scrie singură, fără să moștenească codul lor.
  • interface: Modificator de clasă (Dart 3): în afara fișierului ei, clasa poate fi doar implementată, nu și extinsă.
  • sealed: Clasă cu un set închis de subtipuri, toate în același fișier; switch-ul pe ea verifică dacă ai tratat toate cazurile.
  • factory: Constructor care nu creează neapărat un obiect nou: poate întoarce unul din cache sau o subclasă.