![]() |
Siamo nel pieno del periodo natalizio — e, come si dice, è tempo di decorare! Ma questa volta non parliamo di alberi, lucine o pacchetti: parliamo di come decorare il nostro codice JavaScript per renderlo più elegante e modulare.
No, non useremo la sintassi magica @decorator (ancora non pienamente supportata da tutti gli ambienti), ma vedremo come implementare lo stesso concetto in JavaScript puro, in modo semplice e comprensibile.
Cosa significa “decorare” in JavaScript
In programmazione, “decorare” un elemento significa aggiungere nuove funzionalità senza modificare il codice originale.
Un Decorator è quindi una funzione che prende un’altra funzione, classe o metodo e la avvolge con un nuovo comportamento.
È un pattern molto utile per gestire in modo pulito logiche trasversali come logging, sicurezza, caching o validazione.
Un primo esempio: aggiungere log ai metodi
Immagina di voler sapere quando una funzione viene chiamata e con quali parametri.
Con il pattern dei Decorator possiamo scrivere una funzione che “aggiunge” questa funzionalità a qualsiasi metodo.
function logExecution(fn, name) {
return function (...args) {
console.log(`Calling ${name} with arguments:`, args);
const result = fn.apply(this, args);
console.log(`Result from ${name}:`, result);
return result;
};
}
class Calculator {
add(a, b) {
return a + b;
}
}
// Decoriamo manualmente il metodo
Calculator.prototype.add = logExecution(Calculator.prototype.add, "add");
const calc = new Calculator();
calc.add(2, 3);
👉 In questo esempio, la funzione logExecution riceve il metodo originale, ne crea una versione “decorata” che stampa i log e poi chiama la funzione originale.
Il risultato? Abbiamo aggiunto log automatici senza modificare la logica interna del metodo.
Decorare più metodi con una sola funzione
Possiamo creare una funzione che applichi automaticamente un Decorator a tutti i metodi di una classe:
function decorateAll(target, decorator) {
const methodNames = Object.getOwnPropertyNames(target.prototype)
.filter(name => typeof target.prototype[name] === "function" && name !== "constructor");
for (const name of methodNames) {
const original = target.prototype[name];
target.prototype[name] = decorator(original, name);
}
}
// Usiamo lo stesso decorator di prima
decorateAll(Calculator, logExecution);
const c = new Calculator();
c.add(5, 7);
Con questa tecnica possiamo aggiungere comportamenti comuni a tutte le funzioni di una classe con una sola chiamata — una decorazione “globale”, come mettere un’unica ghirlanda su tutto l’albero 🎄.
Un caso pratico: controllo di accesso in un’API
Un esempio reale in cui i Decorator (anche implementati a mano) possono fare la differenza è nella gestione dell’autenticazione.
Immagina un controller che espone vari metodi API, ma solo alcuni devono essere accessibili a utenti autenticati. Invece di inserire controlli ripetitivi in ogni metodo, possiamo creare un Decorator che li gestisca per noi:
function requireAuth(fn, name) {
return function (...args) {
if (!this.user || !this.user.isAuthenticated) {
throw new Error(`Access denied to ${name}: user not authenticated`);
}
return fn.apply(this, args);
};
}
class UserController {
constructor(user) {
this.user = user;
}
getUserProfile() {
return { name: this.user.name, email: this.user.email };
}
deleteAccount() {
return "Account deleted";
}
}
// Applichiamo il decorator solo ai metodi sensibili
UserController.prototype.getUserProfile =
requireAuth(UserController.prototype.getUserProfile, "getUserProfile");
UserController.prototype.deleteAccount =
requireAuth(UserController.prototype.deleteAccount, "deleteAccount");
const guest = new UserController({ isAuthenticated: false });
const admin = new UserController({ name: "Alice", email: "alice@example.com", isAuthenticated: true });
try {
guest.getUserProfile(); // Lancerà errore
} catch (e) {
console.error(e.message);
}
console.log(admin.getUserProfile()); // Funziona
Con questo approccio il codice rimane pulito, sicuro e riutilizzabile: la logica di autenticazione è concentrata in un solo punto e può essere applicata a qualsiasi metodo senza ripetizione.
🎁 Conclusione
Proprio come le decorazioni natalizie, anche i Decorator vanno usati con gusto: non servono ovunque, ma quando li usi bene rendono il tuo codice più elegante e modulare.
E la cosa bella è che, anche senza nuove sintassi o transpiler, possiamo ottenere gli stessi benefici con JavaScript puro, semplicemente combinando funzioni e classi in modo intelligente.
Buon coding… e buone feste! 🎅✨
📚 Ti sono piaciuti i Decorator?
Se il concetto di decorazione del codice ti ha incuriosito e vuoi approfondire altre tecniche per rendere il tuo JavaScript più elegante, modulare e manutenibile, allora potresti trovare interessante anche questo articolo: The Decorator Pattern in Modern JavaScript: Adding Functionality Without Breaking Code.
Si tratta di un approfondimento su altri pattern e approcci che permettono di estendere il comportamento del codice senza appesantirlo, mantenendo una struttura pulita e facilmente riutilizzabile.
Follow me #techelopment
Official site: www.techelopment.it
facebook: Techelopment
instagram: @techelopment
X: techelopment
Bluesky: @techelopment
telegram: @techelopment_channel
whatsapp: Techelopment
youtube: @techelopment
