Skip to content

Programmation Orientée Objet Dart

Dart propose une POO relativement classique avec des classes pourvues de constructeurs. Il est possible de déclarer des constructeurs nommés, permettant de créer des “configurations” d’instanciation particulières.

void main() {
final counter = ValueNotifier(0);
counter.addListener(() => print('listener 1 : ${counter.value}'));
counter.addListener(() => print('listener 2 : ${counter.value}'));
counter.value = 1;
}
typedef Listener = void Function();
abstract class Notifier {
final _listeners = <Listener>{};
void addListener(Listener listener) {
_listeners.add(listener);
}
void removeListener(Listener listener) {
_listeners.remove(listener);
}
void removeAllListeners() {
_listeners.clear();
}
void notifyListeners() {
for (final listener in _listeners) {
listener.call();
}
}
}
class ValueNotifier<T> extends Notifier {
T _value;
T get value => _value;
set value(T newValue) {
_value = newValue;
notifyListeners();
}
ValueNotifier(T value) : _value = value;
}

En savoir plus

class Response {
final int statusCode;
final String body;
Response({required this.statusCode, required this.body});
Response.ok({required this.body}) : statusCode = 200;
Response.notFound({required this.body}) : statusCode = 404;
}

Un factory constructor peut renvoyer une instance existante :

class Singleton {
static final Singleton _singleton = Singleton._internal();
factory Singleton() {
return _singleton;
}
Singleton._internal();
}

Par défaut, toute class est implicitement une interface. Il est donc possible de l’implémenter ou de l’étendre.

class A {
void hello() {
print('hello');
}
}
final a = A();
a.hello();
class B extends A {}
final b = B();
b.hello();
class C implements A {
void hello() {
print('HELLO');
}
}
final c = C();
c.hello();
  • On ne peut pas les instancier
  • Toutes les méthodes n’ont pas besoin d’être implémentées
abstract class BaseService {
void describe();
void describeWithEmphasis() {
print('=========');
describe();
print('=========');
}
}

En savoir plus sur les classes abstraites

Les mixins permettent d’ajouter un même comportement à d’autres classes.

mixin Piloted {
int astronauts = 1;
void describeCrew() {
print('Number of astronauts: $astronauts');
}
}
class PilotedCraft extends Spacecraft with Piloted {
// ...
}

En savoir plus sur les mixins

Les enums de Dart ont longtemps été très basiques. Dart 2.15 a ajouté quelques utilitaires :

  • MyEnum.values.asNameMap()
  • MyEnum.option1.name
enum Orientation { landscape, portrait }
enum CardType { visa, mastercard }
void main() {
print(CardType.values);
print(CardType.values.asMap());
print(CardType.values.asNameMap());
print(CardType.visa);
print(CardType.visa.name);
print(CardType.visa.index);
print(CardType.values.byName('visa'));
}

Depuis Dart 2.17, les enums peuvent avoir des valeurs associées. Le constructeur doit être constant et les valeurs associées final.

enum Routes {
home('/'),
login('/login'),
details('/details');
final String path;
const Routes(this.path);
}
void main() {
final route = Routes.home;
switch(route) {
case Routes.login:
goToLogin(route.path);
case Routes.home:
goToHome(route.path);
case Routes.details:
goToDetails(route.path);
}
}

Les extensions de méthodes permettent d’ajouter des méthodes et propriétés à d’autres classes. À la différence des mixins, les extensions ont accès aux propriétés et méthodes de la classe qu’elles étendent.

extension SpaceCraftExtension on SpaceCraft {
String get description => '$name / $launchDate';
}

Permet de définir une catégorie de classes énumérables.

sealed class Message {
final String title;
Message(this.title);
}
class TextMessage extends Message {
TextMessage(super.title);
}
class VideoMessage extends Message {
VideoMessage(super.title);
}
Widget buildMessageView(Message message) {
return switch (message) {
TextMessage() => Text('Text: ${message.title}'),
VideoMessage() => VideoPlayer(message.title),
};
}