Menu
Coddy logo textTech

Méthodes d'extension

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

Parfois, vous souhaitez ajouter des fonctionnalités à une classe que vous ne possédez pas - comme les types intégrés String ou int de Dart. Vous ne pouvez pas modifier leur code source, et l'héritage n'est d'aucune aide avec les classes finales. C'est là qu'interviennent les méthodes d'extension.

Les extensions vous permettent d'ajouter de nouvelles méthodes à des types existants sans les modifier ni créer de sous-classes :

extension StringExtras on String {
  String reverse() {
    return split('').reversed.join('');
  }
  
  bool get isPalindrome {
    var cleaned = toLowerCase().replaceAll(' ', '');
    return cleaned == cleaned.split('').reversed.join('');
  }
}

void main() {
  print('hello'.reverse());        // olleh
  print('radar'.isPalindrome);     // true
}

La syntaxe est extension ExtensionName on Type. À l'intérieur, vous définissez des méthodes et des getters tout comme dans une classe ordinaire. Une fois définies, ces méthodes apparaissent sur toutes les instances de ce type comme si elles étaient intégrées.

Les extensions fonctionnent sur n'importe quel type, y compris vos propres classes et les types génériques :

extension IntExtras on int {
  int squared() => this * this;
}

extension ListExtras<T> on List<T> {
  T? get secondOrNull => length >= 2 ? this[1] : null;
}

void main() {
  print(5.squared());                    // 25
  print([1, 2, 3].secondOrNull);         // 2
}

Remarquez qu'à l'intérieur d'une extension, this fait référence à l'instance sur laquelle la méthode est appelée. Les extensions sont un moyen propre d'améliorer les types existants tout en gardant votre code organisé et lisible.

challenge icon

Défi

Facile

Améliorons les types intégrés de Dart avec des fonctionnalités utiles en utilisant des méthodes d'extension ! Vous allez créer des extensions qui ajoutent des méthodes pratiques aux types String et List, puis les utiliser dans votre fichier principal.

Vous organiserez votre code en deux fichiers :

  • extensions.dart : Créez deux extensions qui ajoutent de nouvelles capacités aux types existants :
    • Une extension nommée StringUtils sur String avec :
      • Une méthode countVowels() qui retourne le nombre de voyelles (a, e, i, o, u - insensible à la casse) dans la chaîne
      • Un getter initials qui retourne la première lettre de chaque mot (séparé par des espaces), jointes ensemble et en majuscules. Par exemple, "hello world" devient "HW"
    • Une extension nommée ListUtils<T> sur List<T> avec :
      • Une méthode safeGet(int index) qui retourne l'élément à l'index s'il existe, ou null si l'index est hors limites
      • Un getter hasMultiple qui retourne true si la liste contient plus d'un élément
  • main.dart : Importez vos extensions et faites-en la démonstration :
    • Créez une chaîne "Object Oriented Programming" et affichez son nombre de voyelles au format : Vowels: [count]
    • Affichez les initiales de cette même chaîne au format : Initials: [initials]
    • Créez une liste d'entiers [10, 20, 30]
    • Affichez le résultat de safeGet(1) au format : Element at 1: [value]
    • Affichez le résultat de safeGet(5) au format : Element at 5: [value]
    • Affichez si la liste a plusieurs éléments au format : Has multiple: [true/false]

N'oubliez pas qu'à l'intérieur d'une extension, this fait référence à l'instance sur laquelle la méthode est appelée. Vos extensions donneront l'impression que ces types possèdent ces méthodes de manière native !

Sortie attendue :

Vowels: 9
Initials: OOP
Element at 1: 20
Element at 5: null
Has multiple: true

Aide-mémoire

Les méthodes d'extension vous permettent d'ajouter de nouvelles fonctionnalités à des types existants sans modifier leur code source ni utiliser l'héritage.

La syntaxe pour créer une extension est extension ExtensionName on Type :

extension StringExtras on String {
  String reverse() {
    return split('').reversed.join('');
  }
  
  bool get isPalindrome {
    var cleaned = toLowerCase().replaceAll(' ', '');
    return cleaned == cleaned.split('').reversed.join('');
  }
}

Une fois définies, les méthodes d'extension peuvent être appelées sur des instances de ce type comme s'il s'agissait de méthodes intégrées :

print('hello'.reverse());        // olleh
print('radar'.isPalindrome);     // true

Les extensions fonctionnent sur n'importe quel type, y compris les types intégrés, vos propres classes et les types génériques :

extension IntExtras on int {
  int squared() => this * this;
}

extension ListExtras<T> on List<T> {
  T? get secondOrNull => length >= 2 ? this[1] : null;
}

print(5.squared());                    // 25
print([1, 2, 3].secondOrNull);         // 2

À l'intérieur d'une extension, this fait référence à l'instance sur laquelle la méthode est appelée.

Essayez vous-même

import 'extensions.dart';

void main() {
  // Créer la chaîne de caractères
  String text = "Object Oriented Programming";

  // TODO: Afficher le nombre de voyelles en utilisant countVowels()
  // Format : Vowels: [count]

  // TODO: Afficher les initiales en utilisant le getter initials
  // Format : Initials: [initials]

  // Créer la liste d'entiers
  List<int> numbers = [10, 20, 30];

  // TODO: Afficher le résultat de safeGet(1)
  // Format : Element at 1: [value]

  // TODO: Afficher le résultat de safeGet(5)
  // Format : Element at 5: [value]

  // TODO: Afficher si la liste contient plusieurs éléments
  // Format : Has multiple: [true/false]
}
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