Menu
Coddy logo textTech

Le mot-clé final pour les classes

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

Parfois, vous souhaitez empêcher une classe d'être étendue. Le mot-clé final, lorsqu'il est appliqué à une classe, empêche toute autre classe d'en hériter.

final class DatabaseConnection {
  String connectionString;
  
  DatabaseConnection(this.connectionString);
  
  void connect() {
    print('Connected to $connectionString');
  }
}

// Cela provoquerait une erreur de compilation :
// class CustomConnection extends DatabaseConnection { }

Marquer une classe comme final est utile lorsque son extension pourrait rompre son comportement prévu ou ses garanties de sécurité. Par exemple, une classe qui gère des ressources sensibles pourrait avoir besoin de s'assurer que ses méthodes ne sont pas redéfinies de manière inattendue.

Dart 3 a également introduit des modificateurs associés : base force les sous-classes à utiliser extends (pas implements), et sealed limite l'héritage à la même bibliothèque. Pour l'instant, concentrez-vous sur final comme le moyen le plus simple de verrouiller complètement une classe.

Utilisez les classes final quand vous êtes certain que la conception de la classe est terminée et que l'héritage ne ferait que causer des problèmes. Cependant, n'en abusez pas - la plupart des classes gagnent à rester ouvertes à l'extension.

challenge icon

Défi

Facile

Construisons un système de configuration sécurisé qui démontre quand et pourquoi vous voudriez empêcher une classe d'être étendue. Vous allez créer une classe finale qui gère les paramètres de l'application, garantissant que son comportement ne peut pas être modifié par héritage.

Vous organiserez votre code en deux fichiers :

  • config.dart : Définissez vos classes de configuration ici :
    • Une final class AppConfig qui ne peut pas être étendue. Elle doit avoir une propriété String appName et String version, un constructeur qui prend les deux valeurs, et une méthode display() qui affiche [appName] v[version]
    • Une classe Feature régulière (non finale) avec une propriété String name et bool enabled, un constructeur pour les deux, et une méthode status() qui affiche [name]: [enabled ? 'ON' : 'OFF']
    • Une classe ExperimentalFeature qui étend Feature et ajoute une propriété String warning. Surchargez status() en utilisant @override pour appeler d'abord la version du parent avec super.status(), puis afficher Warning: [warning]
  • main.dart : Importez votre fichier de configuration et démontrez la différence entre les classes finales et régulières :
    • Créez un AppConfig avec appName 'MyApp' et version '2.0.1', puis appelez display()
    • Affichez une ligne vide
    • Créez une Feature avec name 'Dark Mode' et enabled true, puis appelez status()
    • Affichez une ligne vide
    • Créez une ExperimentalFeature avec name 'AI Assistant', enabled false, et warning 'May be unstable', puis appelez status()

Remarquez comment AppConfig est marquée comme final parce que son comportement de configuration doit rester cohérent et sécurisé - aucune sous-classe ne devrait pouvoir modifier la façon dont les paramètres sont gérés. Pendant ce temps, Feature reste ouverte à l'extension, permettant à ExperimentalFeature d'ajouter un comportement spécialisé.

Sortie attendue :

MyApp v2.0.1

Dark Mode: ON

AI Assistant: OFF
Warning: May be unstable

Aide-mémoire

Le mot-clé final empêche une classe d'être étendue :

final class DatabaseConnection {
  String connectionString;
  
  DatabaseConnection(this.connectionString);
  
  void connect() {
    print('Connected to $connectionString');
  }
}

// Cela provoquerait une erreur de compilation :
// class CustomConnection extends DatabaseConnection { }

Utilisez des classes final lorsque leur extension pourrait rompre le comportement prévu ou les garanties de sécurité. La plupart des classes devraient rester ouvertes à l'extension, à moins qu'il n'y ait une raison spécifique de les verrouiller.

Dart 3 propose également les modificateurs base (oblige les sous-classes à utiliser extends) et sealed (limite l'héritage à la même bibliothèque).

Essayez vous-même

import 'config.dart';

void main() {
  // TODO: Créer un AppConfig avec appName 'MyApp' et version '2.0.1'
  // Ensuite, appeler display()
  
  // TODO: Afficher une ligne vide
  
  // TODO: Créer un Feature avec name 'Dark Mode' et enabled true
  // Ensuite, appeler status()
  
  // TODO: Afficher une ligne vide
  
  // TODO: Créer un ExperimentalFeature avec name 'AI Assistant',
  // enabled false, et warning 'May be unstable'
  // Ensuite, appeler status()
}
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