Ce este
Șablonul Decorator adaugă comportament unui obiect învelindu-l într-un alt obiect cu aceeași interfață. Fiecare înveliș își face partea sa suplimentară și transmite apelul mai departe către ceea ce învelește.
Deoarece învelișul și obiectul învelit au aceeași interfață, învelișurile se pot stivui în orice combinație — ca straturile de haine.
Observație: această pagină folosește clase pentru înveliș, pentru că straturile păstrează stare (obiectul pe care îl învelesc) și imbricarea se vede ușor. Un înveliș poate fi la fel de bine o funcție care primește o funcție și returnează una nouă — este același șablon, într-o formă mai mică.
Exemplu: învelirea unui notificator
Notificatorul simplu trimite un e-mail. Un înveliș adaugă jurnalizare înainte de trimitere; altul adaugă un SMS după. Apelantul vede în continuare un simplu Notifier.
Straturi în jurul unui nucleu
new WithLog(new WithSMS(new EmailNotifier())) se citește dinspre interior spre exterior: e-mailul în nucleu, SMS-ul în jurul lui, jurnalizarea cel mai în exterior. Rezultatul arată exact această ordine — linia de jurnal, e-mailul, apoi SMS-ul. Orice strat poate fi adăugat, eliminat sau reordonat fără a atinge celelalte straturi.
Ieșire: program TypeScript și rezultatul capturat
interface Notifier {
send(msg: string): void
}
class EmailNotifier implements Notifier {
send(msg: string): void {
console.log("e-mail:", msg)
}
}
// Fiecare decorator învelește un Notifier și adaugă un strat.
class WithLog implements Notifier {
private wrapped: Notifier
constructor(wrapped: Notifier) {
this.wrapped = wrapped
}
send(msg: string): void {
console.log("jurnal: se trimite o notificare")
this.wrapped.send(msg)
}
}
class WithSMS implements Notifier {
private wrapped: Notifier
constructor(wrapped: Notifier) {
this.wrapped = wrapped
}
send(msg: string): void {
this.wrapped.send(msg)
console.log("sms:", msg)
}
}
const notifier = new WithLog(new WithSMS(new EmailNotifier()))
notifier.send("serverul este oprit")
Când să îl folosești
Folosește-l pentru a adăuga comportament opțional și combinabil — jurnalizare, memorare în cache, reîncercări, metrici — în jurul unui nucleu pe care nu vrei să îl modifici. Middleware-ul din serverele web este exact acest șablon.
Evită-l atunci când comportamentul nu este opțional și nu este combinabil — atunci el aparține chiar clasei, unde este mai ușor de găsit.
Avantaje și dezavantaje
Avantaje: comportamentul este adăugat fără a atinge clasa de bază; straturile se combină liber; fiecare strat este mic și poate fi testat separat.
Dezavantaje: o stivă adâncă de învelișuri este greu de depanat — apelul parcurge un drum lung înainte să facă ceva; liniile de construcție devin lungi.