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 héritage - en utilisant un type de classe parente pour travailler avec des objets enfants. Mais le polymorphisme fonctionne également via des 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 de hiérarchie d’héritage. N’importe quelle classe peut implémenter une interface, quel que soit ce dont elle hérite. 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.
Défi
FacileConstruisons un système de lecteur multimédia qui démontre le polymorphisme par le biais d’interfaces. Vous allez créer une interface qui définit ce que signifie être « lisible », puis implémenter plusieurs types de médias sans lien entre eux qui respectent tous ce contrat, ce qui permet de les traiter uniformément 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
Playableavec deux méthodes abstraites :play()etString getMediaType() - Une classe
Songqui implémentePlayable. Elle doit avoir unString titleet unString artist. Sa méthodeplay()affichePlaying song: [title] by [artist]etgetMediaType()renvoie'Audio' - Une classe
Videoqui implémentePlayable. Elle doit avoir unString titleet unint duration(en minutes). Sa méthodeplay()affichePlaying video: [title] ([duration] min)etgetMediaType()renvoie'Video' - Une classe
Podcastqui implémentePlayable. Elle doit avoir unString titleet unint episode. Sa méthodeplay()affichePlaying podcast: [title] - Episode [episode]etgetMediaType()renvoie'Podcast'
playAll(List<Playable> playlist)qui parcourt la liste et, pour chaque élément, affiche[Media Type]:, puis appelleplay()sur cet élément.- Une classe abstraite
main.dart: importez votre fichier de médias et démontrez le polymorphisme fondé sur une interface :- Créez une
List<Playable>contenant unSongdont le titre est'Imagine'et l’artiste'John Lennon', unVideodont le titre est'Dart Tutorial'et la durée est15, ainsi qu’unPodcastdont le titre est'Tech Talk'et le numéro d’épisode est42 - Passez cette liste à
playAll()
- Créez une
Remarquez que Song, Video et Podcast ne partagent aucune classe parente : ce sont des types complètement indépendants. Pourtant, comme ils implémentent tous Playable, vous pouvez les stocker dans la même liste et les traiter uniformément par l’intermédiaire de l’interface.
Résultat attendu :
Audio:
Playing song: Imagine by John Lennon
Video:
Playing video: Dart Tutorial (15 min)
Podcast:
Playing podcast: Tech Talk - Episode 42Essayez 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()
}
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
1Fondamentaux de la POO
Fichiers externesBibliothèques et importsIntroduction à la POOClasses vs objetsLe mot-clé thisMéthodesVariables d’instanceBases des constructeursRécapitulatif - Calculatrice simple4Sécurité face aux valeurs nulles
Introduction à la sécurité face aux valeurs nullesNullable vs Non-NullableLes opérateurs ? et !Mot-clé Late et sécurité face aux valeurs nullesOpérateurs sensibles à nullSécurité face aux valeurs nulles dans les classesRécapitulatif – Système de profil utilisateur7Classes abstraites et interfaces
Classes abstraitesMéthodes abstraitesInterfaces en DartInterfaces implicitesImplémenter ou étendreInterfaces multiplesRécapitulatif - Calculateur de formes10Collections et génériques
Vue d’ensemble des List, Set et MapCollections à typage sûrClasses génériquesMéthodes génériquesContraintes génériquesIterable et IteratorRécapitulatif – stockage générique2Constructeurs en Dart
Constructeur par défautConstructeurs nommésListes d'initialisationConstructeurs constantsConstructeurs factoryConstructeurs redirigésRécapitulatif - Constructeur de formes5Encapsulation
Membres publics vs privésLa convention du préfixe _Confidentialité au niveau de la bibliothèqueApprofondissement des getters et settersMasquage de l’informationRécapitulatif - Fiches des étudiants8Mixins
Introduction aux MixinsCréer des MixinsUtiliser plusieurs MixinsMot-clé on dans les MixinsMixin ou héritageMixin ou interfaceRécapitulatif - Système animal11Méthodes spéciales
Redéfinition de toString()Redéfinition de hashCode et ==Interface ComparableMéthode call()Redéfinition de noSuchMethodRécapitulatif - Collection personnalisée14Patrons de conception, partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FactoryPatron ObserverPatron Strategy3Propriétés des classes
Membres d’instance et statiquesChamps Final et ConstVariables différéesMéthodes et champs statiquesAccesseurs et mutateursRécapitulatif - Gestionnaire de compte bancaire6Héritage
Héritage de baseLe mot-clé superRedéfinition de méthodeL’annotation @overrideLe mot-clé de classe finalConstructeurs et héritageRécapitulatif – Hiérarchie des employés9Polymorphisme
Bases du polymorphismePolymorphisme via les interfacesVérification des types à l’exécutionLes opérateurs is et asMot-clé covariantRécapitulatif - Processeur de paiements12POO asynchrone
Futures et async/awaitNotions de base des StreamsContrôleurs de StreamsConstructeurs asynchronesAsynchrone dans les méthodes de classeRécapitulatif - récupérateur de données15Patrons de conception – Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode modèlePatron ÉtatPatron CompositePatron DépôtEntraînez-vous par vous-même : Compilateur Dart en ligne