Menu
Coddy logo textTech

Polymorphisme via les interfaces

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

Dans la leçon précédente, vous avez vu le polymorphisme par l'héritage - en utilisant un type de classe parente pour travailler avec des objets enfants. Mais le polymorphisme fonctionne également via les interfaces, et cette approche est souvent plus flexible.

Lorsque des classes implémentent la même interface, vous pouvez les traiter de manière polymorphe même si elles n'ont aucune relation d'héritage :

abstract class Printable {
  void printDetails();
}

class Invoice implements Printable {
  @override
  void printDetails() => print('Invoice #1234');
}

class Report implements Printable {
  @override
  void printDetails() => print('Monthly Report');
}

class Receipt implements Printable {
  @override
  void printDetails() => print('Receipt for purchase');
}

void printAll(List<Printable> items) {
  for (var item in items) {
    item.printDetails();
  }
}

void main() {
  var documents = [Invoice(), Report(), Receipt()];
  printAll(documents);
}

Invoice, Report et Receipt sont des classes totalement indépendantes - elles ne partagent pas de parent. Pourtant, parce qu'elles implémentent toutes Printable, nous pouvons les stocker dans la même liste et appeler printDetails() sur chacune d'elles.

C'est puissant car cela vous permet de définir des contrats de comportement sans imposer une hiérarchie d'héritage. N'importe quelle classe peut implémenter une interface, quel que soit ce qu'elle étend. Votre code devient plus modulaire puisque vous pouvez ajouter de nouveaux types imprimables sans modifier le code existant - il suffit d'implémenter l'interface.

challenge icon

Défi

Facile

Construisons un système de lecteur multimédia qui démontre le polymorphisme à travers les interfaces. Vous allez créer une interface qui définit ce que signifie être « jouable », puis implémenter plusieurs types de médias non liés qui remplissent tous ce contrat - ce qui permet de les manipuler de manière uniforme malgré l'absence de relation d'héritage.

Vous organiserez votre code en deux fichiers :

  • media.dart : Définissez votre interface et vos classes de médias ici :
    • Une classe abstraite Playable avec deux méthodes abstraites : play() et String getMediaType()
    • Une classe Song qui implémente Playable. Elle doit avoir un String title et un String artist. Sa méthode play() affiche Playing song: [title] by [artist] et getMediaType() retourne 'Audio'
    • Une classe Video qui implémente Playable. Elle doit avoir un String title et un int duration (en minutes). Sa méthode play() affiche Playing video: [title] ([duration] min) et getMediaType() retourne 'Video'
    • Une classe Podcast qui implémente Playable. Elle doit avoir un String title et un int episode. Sa méthode play() affiche Playing podcast: [title] - Episode [episode] et getMediaType() retourne 'Podcast'
    Créez également une fonction playAll(List<Playable> playlist) qui parcourt la liste et, pour chaque élément, affiche [Media Type]: suivi de l'appel de play() sur cet élément.
  • main.dart : Importez votre fichier média et démontrez le polymorphisme basé sur l'interface :
    • Créez une List<Playable> contenant une Song avec le titre 'Imagine' et l'artiste 'John Lennon', une Video avec le titre 'Dart Tutorial' et la durée 15, et un Podcast avec le titre 'Tech Talk' et l'épisode 42
    • Passez cette liste à playAll()

Remarquez comment Song, Video et Podcast ne partagent aucune classe parente - ce sont des types complètement distincts. Pourtant, parce qu'ils implémentent tous Playable, vous pouvez les stocker dans la même liste et les traiter de manière uniforme via l'interface.

Sortie attendue :

Audio:
Playing song: Imagine by John Lennon
Video:
Playing video: Dart Tutorial (15 min)
Podcast:
Playing podcast: Tech Talk - Episode 42

Aide-mémoire

Le polymorphisme fonctionne via des interfaces, permettant à des classes non liées d'être traitées de manière uniforme sans relations d'héritage.

Les classes implémentant la même interface peuvent être utilisées de manière polymorphe :

abstract class Printable {
  void printDetails();
}

class Invoice implements Printable {
  @override
  void printDetails() => print('Invoice #1234');
}

class Report implements Printable {
  @override
  void printDetails() => print('Monthly Report');
}

void printAll(List<Printable> items) {
  for (var item in items) {
    item.printDetails();
  }
}

void main() {
  var documents = [Invoice(), Report()];
  printAll(documents);
}

Le polymorphisme basé sur les interfaces vous permet de :

  • Définir des contrats de comportement sans imposer de hiérarchies d'héritage
  • Stocker des types non liés dans la même collection
  • Ajouter de nouveaux types sans modifier le code existant
  • Rendre le code plus modulaire et flexible

Essayez vous-même

import 'media.dart';

void main() {
  // TODO: Créer une List<Playable> contenant :
  // - Une Song avec le titre 'Imagine' et l'artiste 'John Lennon'
  // - Une Video avec le titre 'Dart Tutorial' et la durée 15
  // - Un Podcast avec le titre 'Tech Talk' et l'épisode 42
  
  // TODO: Passer la liste à playAll()
}
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