Extension functions/Erweiterungen sind ein Mechanismus, der es ermöglicht, neue Funktionen zu bereits bestehenden Klassen hinzuzufügen, ohne dass eine Vererbung oder Änderung der Klasse selbst erforderlich ist.
Zum Beispiel, für die Klasse String, fügen wir eine Funktion hinzu, die den String umkehrt:
fun String.reverse(): String { return this.reversed() } println("abc".reverse()) // "cba"
Erweiterungen modifizieren die Klasse tatsächlich nicht, sie sind einfach syntaktischer Zucker: Sie werden als statische Methoden kompiliert, die eine Instanz des Objekts als ersten Parameter akzeptieren.
Vorteile: Kürze, Lesbarkeit, Erweiterbarkeit des Codes. Sie eignen sich gut für Utility-Funktionen für Sammlungen, Strings usw.
Fallstricke:
Kann man mit Hilfe von Extension Functions eine neue Variable (Property), die den Zustand speichert, zur Klasse hinzufügen?
Ergebnis: Nein. Extension property ist immer eine berechnete Eigenschaft (Getter/Setter), kein Feld. Sie können keinen Zustand speichern – nur zur Laufzeit berechnen.
val String.secondChar: Char get() = this[1] // Nur Berechnung, kein Speichern!
Geschichte
In einem Projekt zur Datenverifikation fügte ein Entwickler eine Extension Property zur Modell-Klasse hinzu, als ob sie einen Wert speichern würde, stellte aber später fest, dass der Wert immer berechnet wird und nicht gespeichert wird, was dazu führte, dass die Logik bei mehrfachen Aufrufen falsch funktionierte.
Geschichte
In einer großen Anwendung wurden die Erweiterungen genauso benannt wie die Methoden der Klasse, was zu Verwirrung führte: Die Methoden der Klasse hatten immer Vorrang, und die Erweiterungen wurden nicht aufgerufen – ein ganzer Tag wurde mit dem Debuggen von "unsichtbarem" Code verbracht.
Geschichte
In einer der Bibliotheken wurden Erweiterungen für private Felder der Klasse verwendet, stellte sich jedoch heraus, dass sie überhaupt keinen Zugriff auf private haben, was dazu führte, dass die Architektur der Modelle refaktoriert werden musste.