Extension Methods
Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy — Lektion 83 von 110.
Manchmal möchten Sie Funktionalität zu einer Klasse hinzufügen, die Ihnen nicht gehört – wie die in Dart integrierten Typen String oder int. Sie können deren Quellcode nicht ändern, und Vererbung hilft bei finalen Klassen nicht weiter. Hier kommen Extension-Methoden ins Spiel.
Extensions ermöglichen es Ihnen, bestehenden Typen neue Methoden hinzuzufügen, ohne diese zu ändern oder Unterklassen zu erstellen:
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
}Die Syntax lautet extension ExtensionName on Type. Darin definieren Sie Methoden und Getter genau wie in einer regulären Klasse. Einmal definiert, erscheinen diese Methoden auf allen Instanzen dieses Typs, als wären sie integriert.
Extensions funktionieren mit jedem Typ, einschließlich Ihrer eigenen Klassen und generischen Typen:
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
}Beachten Sie, dass innerhalb einer Erweiterung this auf die Instanz verweist, auf der die Methode aufgerufen wird. Erweiterungen sind eine saubere Möglichkeit, bestehende Typen zu verbessern und gleichzeitig Ihren Code organisiert und lesbar zu halten.
Aufgabe
EinfachLassen Sie uns die integrierten Typen von Dart mit nützlichen Funktionen mithilfe von Extension Methods erweitern! Sie werden Erweiterungen erstellen, die den Typen String und List hilfreiche Methoden hinzufügen, und diese dann in Ihrer Hauptdatei verwenden.
Sie werden Ihren Code in zwei Dateien organisieren:
extensions.dart: Erstellen Sie zwei Erweiterungen, die bestehenden Typen neue Funktionen hinzufügen:- Eine Erweiterung namens
StringUtilsfürStringmit:- Einer Methode
countVowels(), die die Anzahl der Vokale (a, e, i, o, u - unabhängig von Groß-/Kleinschreibung) im String zurückgibt - Einem Getter
initials, der den ersten Buchstaben jedes Wortes (getrennt durch Leerzeichen) zurückgibt, zusammengefügt und in Großbuchstaben umgewandelt. Zum Beispiel wird"hello world"zu"HW"
- Einer Methode
- Eine Erweiterung namens
ListUtils<T>fürList<T>mit:- Einer Methode
safeGet(int index), die das Element an dem Index zurückgibt, falls es existiert, odernull, falls der Index außerhalb des Bereichs liegt - Einem Getter
hasMultiple, dertruezurückgibt, wenn die Liste mehr als ein Element enthält
- Einer Methode
- Eine Erweiterung namens
main.dart: Importieren Sie Ihre Erweiterungen und demonstrieren Sie diese in Aktion:- Erstellen Sie einen String
"Object Oriented Programming"und geben Sie dessen Vokalanzahl im FormatVowels: [count]aus - Geben Sie die Initialen desselben Strings im Format
Initials: [initials]aus - Erstellen Sie eine Liste von Ganzzahlen
[10, 20, 30] - Geben Sie das Ergebnis von
safeGet(1)im FormatElement at 1: [value]aus - Geben Sie das Ergebnis von
safeGet(5)im FormatElement at 5: [value]aus - Geben Sie aus, ob die Liste mehrere Elemente hat, im Format:
Has multiple: [true/false]
- Erstellen Sie einen String
Denken Sie daran, dass innerhalb einer Erweiterung this sich auf die Instanz bezieht, auf der die Methode aufgerufen wird. Ihre Erweiterungen werden dafür sorgen, dass sich diese Typen so anfühlen, als hätten sie diese Methoden fest eingebaut!
Erwartete Ausgabe:
Vowels: 9
Initials: OOP
Element at 1: 20
Element at 5: null
Has multiple: trueSpickzettel
Erweiterungsmethoden (Extension methods) ermöglichen es Ihnen, bestehenden Typen neue Funktionalitäten hinzuzufügen, ohne deren Quellcode zu ändern oder Vererbung zu nutzen.
Die Syntax zum Erstellen einer Erweiterung lautet 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('');
}
}Einmal definiert, können Erweiterungsmethoden auf Instanzen dieses Typs so aufgerufen werden, als wären sie integriert:
print('hello'.reverse()); // olleh
print('radar'.isPalindrome); // trueErweiterungen funktionieren bei jedem Typ, einschließlich integrierter Typen, eigener Klassen und generischer Typen:
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); // 2Innerhalb einer Erweiterung bezieht sich this auf die Instanz, auf der die Methode aufgerufen wird.
Probier es selbst
import 'extensions.dart';
void main() {
// Erstelle den String
String text = "Object Oriented Programming";
// TODO: Gib die Anzahl der Vokale mit countVowels() aus
// Format: Vowels: [count]
// TODO: Gib die Initialen mit dem initials Getter aus
// Format: Initials: [initials]
// Erstelle die Liste von Ganzzahlen
List<int> numbers = [10, 20, 30];
// TODO: Gib das Ergebnis von safeGet(1) aus
// Format: Element at 1: [value]
// TODO: Gib das Ergebnis von safeGet(5) aus
// Format: Element at 5: [value]
// TODO: Gib aus, ob die Liste mehrere Elemente hat
// Format: Has multiple: [true/false]
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienBibliotheken & ImportsEinführung in die OOPKlassen vs. ObjekteDas this-SchlüsselwortMethodenInstanzvariablenKonstruktor-GrundlagenWiederholung – Einfacher Taschenrechner4Null-Sicherheit
Einführung in Null-SicherheitNullable vs. Non-NullableDie ? und ! OperatorenLate-Schlüsselwort & Null-SicherheitNull-aware OperatorenNull-Sicherheit in KlassenZusammenfassung – Benutzerprofil-System7Abstrakte Klassen & Interfaces
Abstrakte KlassenAbstrakte MethodenInterfaces in DartImplizite InterfacesImplementieren vs. ErweiternMehrfache InterfacesRückblick – Shape Calculator10Collections & Generics
Überblick über List, Set und MapTypsichere CollectionsGenerische KlassenGenerische MethodenGenerische ConstraintsIterable & IteratorZusammenfassung – Generische Speicherung13Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungExtension MethodsCallable ClassesSealed Classes (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums mit Methoden16Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen2Konstruktoren in Dart
Standard-KonstruktorBenannte KonstruktorenInitialisierungslistenKonstante KonstruktorenFactory-KonstruktorenWeiterleitende KonstruktorenZusammenfassung – Shape Builder5Kapselung
Öffentliche vs. private MemberDie _ Präfix-KonventionSichtbarkeit auf Library-EbeneGetter & Setter im DetailInformation HidingRückblick – Schülerdatensätze8Mixins
Einführung in MixinsMixins erstellenMehrere Mixins verwendenDas on-Schlüsselwort in MixinsMixin vs. VererbungMixin vs. InterfaceZusammenfassung - Tiersystem11Spezielle Methoden
toString() überschreibenhashCode & == überschreibenComparable-Interfacecall()-MethodenoSuchMethod überschreibenZusammenfassung – Eigene Collection14Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster3Klasseneigenschaften
Instanz- vs. statische MemberFinal & Const FelderLate-VariablenStatische Methoden & FelderGetter und SetterZusammenfassung – Bankkonto-Manager6Vererbung
Grundlagen der VererbungDas super-SchlüsselwortMethoden überschreibenDie @override-AnnotationDas final-Klassen-SchlüsselwortKonstruktoren & VererbungRückblick – Mitarbeiter-Hierarchie9Polymorphismus
Polymorphismus-GrundlagenPolymorphismus über InterfacesTypprüfung zur LaufzeitDie is & as OperatorenDas covariant SchlüsselwortZusammenfassung – Payment Processor