Menu
Coddy logo textTech

Das final-Klassen-Schlüsselwort

Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy — Lektion 40 von 110.

Manchmal möchte man verhindern, dass eine Klasse erweitert wird. Das Schlüsselwort final verhindert, wenn es auf eine Klasse angewendet wird, dass andere Klassen von ihr erben.

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

// Dies würde einen Kompilierzeitfehler verursachen:
// class CustomConnection extends DatabaseConnection { }

Eine Klasse als final zu kennzeichnen ist nützlich, wenn deren Erweiterung ihr beabsichtigtes Verhalten oder ihre Sicherheitsgarantien beeinträchtigen könnte. Zum Beispiel muss eine Klasse, die sensible Ressourcen verwaltet, möglicherweise sicherstellen, dass ihre Methoden nicht auf unerwartete Weise überschrieben werden.

Dart 3 hat auch verwandte Modifikatoren eingeführt: base zwingt Unterklassen dazu, extends (nicht implements) zu verwenden, und sealed beschränkt die Vererbung auf dieselbe Bibliothek. Konzentrieren Sie sich vorerst auf final als einfachste Methode, um eine Klasse vollständig abzusperren.

Verwenden Sie final-Klassen, wenn Sie sicher sind, dass das Klassendesign abgeschlossen ist und Vererbung nur Probleme verursachen würde. Verwenden Sie es jedoch nicht zu oft – die meisten Klassen profitieren davon, für Erweiterungen offen zu bleiben.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein sicheres Konfigurationssystem erstellen, das zeigt, wann und warum man verhindern möchte, dass eine Klasse erweitert wird. Sie werden eine finale Klasse erstellen, die Anwendungseinstellungen verwaltet und sicherstellt, dass ihr Verhalten nicht durch Vererbung geändert werden kann.

Sie werden Ihren Code in zwei Dateien organisieren:

  • config.dart: Definieren Sie hier Ihre Konfigurationsklassen:
    • Eine final class AppConfig, die nicht erweitert werden kann. Sie sollte eine String appName und eine String version Eigenschaft haben, einen Konstruktor, der beide Werte entgegennimmt, und eine Methode display(), die [appName] v[version] ausgibt.
    • Eine reguläre (nicht-finale) Feature Klasse mit einer String name und einer bool enabled Eigenschaft, einem Konstruktor für beide und einer Methode status(), die [name]: [enabled ? 'ON' : 'OFF'] ausgibt.
    • Eine ExperimentalFeature Klasse, die Feature erweitert und eine String warning Eigenschaft hinzufügt. Überschreiben Sie status() mit @override, um zuerst die Version der Elternklasse mit super.status() aufzurufen und dann Warning: [warning] auszugeben.
  • main.dart: Importieren Sie Ihre Konfigurationsdatei und demonstrieren Sie den Unterschied zwischen finalen und regulären Klassen:
    • Erstellen Sie eine AppConfig mit appName 'MyApp' und version '2.0.1', und rufen Sie dann display() auf.
    • Geben Sie eine Leerzeile aus.
    • Erstellen Sie ein Feature mit name 'Dark Mode' und enabled true, und rufen Sie dann status() auf.
    • Geben Sie eine Leerzeile aus.
    • Erstellen Sie ein ExperimentalFeature mit name 'AI Assistant', enabled false und warning 'May be unstable', und rufen Sie dann status() auf.

Beachten Sie, dass AppConfig als final markiert ist, da sein Konfigurationsverhalten konsistent und sicher bleiben soll – keine Unterklasse sollte in der Lage sein, die Verwaltung der Einstellungen zu ändern. Währenddessen bleibt Feature offen für Erweiterungen, was es ExperimentalFeature ermöglicht, spezialisiertes Verhalten hinzuzufügen.

Erwartete Ausgabe:

MyApp v2.0.1

Dark Mode: ON

AI Assistant: OFF
Warning: May be unstable

Spickzettel

Das Schlüsselwort final verhindert, dass eine Klasse erweitert wird:

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

// Dies würde einen Kompilierzeitfehler verursachen:
// class CustomConnection extends DatabaseConnection { }

Verwenden Sie final Klassen, wenn deren Erweiterung das beabsichtigte Verhalten oder Sicherheitsgarantien beeinträchtigen könnte. Die meisten Klassen sollten für Erweiterungen offen bleiben, sofern es keinen spezifischen Grund gibt, sie einzuschränken.

Dart 3 bietet außerdem die Modifikatoren base (zwingt Unterklassen dazu, extends zu verwenden) und sealed (beschränkt die Vererbung auf dieselbe Bibliothek) an.

Probier es selbst

import 'config.dart';

void main() {
  // TODO: Erstelle eine AppConfig mit appName 'MyApp' und version '2.0.1'
  // Rufe dann display() auf
  
  // TODO: Gib eine Leerzeile aus
  
  // TODO: Erstelle ein Feature mit name 'Dark Mode' und enabled true
  // Rufe dann status() auf
  
  // TODO: Gib eine Leerzeile aus
  
  // TODO: Erstelle ein ExperimentalFeature mit name 'AI Assistant',
  // enabled false und warning 'May be unstable'
  // Rufe dann status() auf
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung