Decorator-Muster (Dekorierer)
Kurz: Das Decorator-Muster erweitert ein Objekt um zusätzliche Funktionen, indem man es in ein Hüllobjekt mit derselben Schnittstelle verpackt – ohne die Klasse zu ändern oder davon zu erben.
Genauer: Mehrere Dekoratoren lassen sich ineinander stecken, zum Beispiel Logging, Caching, Berechtigungsprüfung und Zeitmessung um dieselbe Funktion. Python hat dafür eine eigene Syntax (@dekorator), JavaScript/TypeScript kennt Decorators für Klassen, Java nutzt es bei Streams (new BufferedReader(new FileReader(...))).
Im Detail
import time
from functools import wraps
def zeitmessung(f):
@wraps(f)
def huelle(*args, **kwargs):
start = time.perf_counter()
ergebnis = f(*args, **kwargs)
print(f"{f.__name__} dauerte {time.perf_counter() - start:.4f} s")
return ergebnis
return huelle
def nur_angemeldet(f):
@wraps(f)
def huelle(benutzer, *args, **kwargs):
if not benutzer:
raise PermissionError("Bitte anmelden")
return f(benutzer, *args, **kwargs)
return huelle
@zeitmessung
@nur_angemeldet
def bericht(benutzer):
return f"Bericht für {benutzer}"
print(bericht("Mia"))Objektorientierte Variante
interface Kaffee { double preis(); String text(); }
class Espresso implements Kaffee { public double preis() { return 2.0; } public String text() { return "Espresso"; } }
class MitMilch implements Kaffee {
private final Kaffee innen;
MitMilch(Kaffee k) { innen = k; }
public double preis() { return innen.preis() + 0.5; }
public String text() { return innen.text() + " mit Milch"; }
}
// new MitMilch(new MitMilch(new Espresso())) -> "Espresso mit Milch mit Milch", 3.0Abgrenzung
Vererbung legt Erweiterungen beim Schreiben fest (Vererbung); Dekoratoren kombinieren sie zur Laufzeit beliebig. Das Muster hängt eng mit Closures und Funktionen höherer Ordnung zusammen, die Funktionen als Werte übernehmen und zurückgeben.
Siehe auch: Higher-Order-Funktion, Annotationen, Strategy-Muster, Vererbung