Menu
Coddy logo textTech

Interfaces implicites

Fait partie de la section Programmation Orientée Objet du Journey Dart de Coddy — leçon 46 sur 110.

Puisque chaque classe Dart définit automatiquement une interface, vous pouvez utiliser n'importe quelle classe comme interface - même des classes concrètes avec des implémentations complètes. C'est ce que nous appelons une interface implicite.

Considérez une classe avec des propriétés et des méthodes :

class Logger {
  String prefix = '[LOG]';
  
  void log(String message) {
    print('$prefix $message');
  }
  
  void clear() {
    print('Clearing logs...');
  }
}

Lorsqu'une autre classe implémente Logger, elle doit fournir sa propre implémentation pour tout - y compris la propriété prefix :

class FileLogger implements Logger {
  @override
  String prefix = '[FILE]';
  
  @override
  void log(String message) {
    print('$prefix Writing to file: $message');
  }
  
  @override
  void clear() {
    print('Deleting log file...');
  }
}

C'est l'idée fondamentale : lorsque vous utilisez implements, vous dites « ma classe aura la même forme » — les mêmes méthodes et propriétés. Vous n'héritez d'aucun code, constructeur ou valeur par défaut. Vous promettez seulement de respecter la structure de l'interface.

Cela rend les interfaces implicites puissantes pour créer des composants interchangeables. Le code qui attend un Logger peut fonctionner avec n'importe quelle classe qui implémente son interface, quelle que soit la manière dont cette implémentation fonctionne en interne.

challenge icon

Défi

Facile

Construisons un système de notification qui démontre comment les classes concrètes peuvent servir d'interfaces implicites. Vous allez créer une classe de notification de base, puis l'implémenter de manière complètement différente, montrant que implements vous oblige à fournir vous-même tous les membres.

Vous organiserez votre code en deux fichiers :

  • notification.dart : Définissez vos classes de notification ici :
    • Une classe Notification avec une propriété String channel définie sur 'default', une méthode send(String message) qui affiche [channel]: [message], et une méthode getStatus() qui retourne la chaîne 'Notification ready'
    • Une classe EmailNotification qui implémente Notification. Puisque vous utilisez implements, vous devez fournir votre propre propriété channel (définissez-la sur 'email'), votre propre méthode send() qui affiche Sending email: [message], et votre propre méthode getStatus() qui retourne 'Email service active'
    • Une classe PushNotification qui implémente Notification. Définissez son channel sur 'push', faites en sorte que send() affiche Push alert: [message], et que getStatus() retourne 'Push service connected'
  • main.dart : Importez votre fichier de notification et démontrez comment différentes classes peuvent implémenter la même interface implicite avec des comportements complètement différents :
    • Créez une instance de EmailNotification et une de PushNotification
    • Pour chaque notification, affichez son statut en utilisant getStatus(), puis appelez send() avec le message 'Hello World'
    • Affichez une ligne vide entre les deux notifications

Rappel : lorsque vous utilisez implements, vous n'héritez d'aucun code de Notification. Vous promettez seulement que votre classe aura la même forme - les mêmes propriétés et méthodes. Chaque classe d'implémentation fournit sa propre implémentation complète.

Résultat attendu :

Email service active
Sending email: Hello World

Push service connected
Push alert: Hello World

Aide-mémoire

En Dart, chaque classe définit automatiquement une interface implicite. Cela signifie que vous pouvez utiliser n'importe quelle classe comme une interface, même les classes concrètes avec des implémentations complètes.

Lorsqu'une classe utilise implements, elle doit fournir sa propre implémentation pour toutes les propriétés et méthodes de l'interface. Vous n'héritez d'aucun code, constructeur ou valeur par défaut - vous promettez seulement de respecter la structure de l'interface.

Exemple d'une classe concrète :

class Logger {
  String prefix = '[LOG]';
  
  void log(String message) {
    print('$prefix $message');
  }
  
  void clear() {
    print('Clearing logs...');
  }
}

Implémentation de l'interface implicite :

class FileLogger implements Logger {
  @override
  String prefix = '[FILE]';
  
  @override
  void log(String message) {
    print('$prefix Writing to file: $message');
  }
  
  @override
  void clear() {
    print('Deleting log file...');
  }
}

Cela rend les interfaces implicites puissantes pour créer des composants interchangeables. Le code qui attend un Logger peut fonctionner avec n'importe quelle classe qui implémente son interface, quelle que soit l'implémentation interne.

Essayez vous-même

import 'notification.dart';

void main() {
  // TODO: Créer une instance de EmailNotification
  
  // TODO: Afficher le statut de la notification par e-mail en utilisant getStatus()
  
  // TODO: Envoyer un message 'Hello World' en utilisant la notification par e-mail
  
  // TODO: Afficher une ligne vide
  
  // TODO: Créer une instance de PushNotification
  
  // TODO: Afficher le statut de la notification push en utilisant getStatus()
  
  // TODO: Envoyer un message 'Hello World' en utilisant la notification push
  
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet