Quali pattern di progettazione hai utilizzato nella pratica?
sobes.tech AI
Risposta dell'AI
Nella pratica, ho applicato i seguenti pattern di progettazione:
-
Metodo Factory (Factory Method): Per creare oggetti di diversi tipi senza specificare la classe concreta di creazione. Utile quando si lavora con diverse fonti di dati o configurazioni.
// Esempio di utilizzo del metodo factory class DataReader { read() { throw new Error("Metodo non implementato"); } } class FileReader extends DataReader { read() { console.log("Leggendo dati dal file..."); } } class NetworkReader extends DataReader { read() { console.log("Leggendo dati dalla rete..."); } } class DataReaderFactory { createReader(type) { switch (type) { case "file": return new FileReader(); case "network": return new NetworkReader(); default: throw new Error("Tipo di reader sconosciuto"); } } } const factory = new DataReaderFactory(); const fileReader = factory.createReader("file"); fileReader.read(); -
Singleton (Singleton): Per garantire che esista solo un'istanza di una classe e fornire un punto di accesso globale ad essa. Spesso usato per gestori di configurazione o connessioni a database.
// Esempio di utilizzo del singleton class ConfigManager { constructor() { if (ConfigManager.instance) { return ConfigManager.instance; } this.config = {}; ConfigManager.instance = this; } setConfig(key, value) { this.config[key] = value; } getConfig(key) { return this.config[key]; } } const instance1 = new ConfigManager(); const instance2 = new ConfigManager(); console.log(instance1 === instance2); // true -
Osservatore (Observer): Per implementare la relazione "uno a molti", dove la modifica dello stato di un oggetto (emittente) comporta automaticamente la notifica di tutti gli oggetti dipendenti (sottoscrittori). Usato in sistemi di notifica, interfacce reattive.
// Esempio di utilizzo dell'osservatore class Observable { constructor() { this.observers = []; } subscribe(observer) { this.observers.push(observer); } unsubscribe(observer) { this.observers = this.observers.filter(obs => obs !== observer); } notify(data) { this.observers.forEach(observer => observer.update(data)); } } class Observer { update(data) { console.log("Aggiornamento ricevuto:", data); } } const observable = new Observable(); const observer1 = new Observer(); const observer2 = new Observer(); observable.subscribe(observer1); observable.subscribe(observer2); observable.notify("Nuovi dati disponibili!"); -
Strategia (Strategy): Per definire una famiglia di algoritmi, incapsularli e renderli intercambiabili. Permette che l'algoritmo vari indipendentemente dai clienti che lo utilizzano. Applicato in diverse varianti di elaborazione dati o esecuzione di operazioni.
// Esempio di utilizzo della strategia class PaymentStrategy { pay(amount) { throw new Error("Metodo non implementato"); } } class CreditCardPayment extends PaymentStrategy { pay(amount) { console.log(`Pagamento di ${amount} con carta di credito`); } } class PayPalPayment extends PaymentStrategy { pay(amount) { console.log(`Pagamento di ${amount} tramite PayPal`); } } class PaymentContext { setStrategy(strategy) { this.strategy = strategy; } executePayment(amount) { this.strategy.pay(amount); } } const context = new PaymentContext(); context.setStrategy(new CreditCardPayment()); context.executePayment(100); context.setStrategy(new PayPalPayment()); context.executePayment(50); -
Decoratore (Decorator): Per aggiungere funzionalità nuove a un oggetto in modo dinamico, senza modificarne la struttura. Avvolge l'oggetto esistente, fornendo la stessa interfaccia dell'oggetto avvolto, ma con funzionalità aggiuntive. Utile per logging, validazione, caching.
// Esempio di utilizzo del decorator class Component { operation() { return "Component di base"; } } class Decorator { constructor(component) { this.component = component; } operation() { return this.component.operation(); } } class ConcreteDecoratorA extends Decorator { operation() { return `DecoratoreConcretoA(${super.operation()})`; } } class ConcreteDecoratorB extends Decorator { operation() { return `DecoratoreConcretoB(${super.operation()})`; } } const simple = new Component(); console.log(simple.operation()); const decoratorA = new ConcreteDecoratorA(simple); console.log(decoratorA.operation()); const decoratorB = new ConcreteDecoratorB(decoratorA); console.log(decoratorB.operation()); -
Modulo (Module): Sebbene il sistema di moduli di Node.js sia integrato (CommonJS, ES Modules), il pattern Module pattern in JavaScript (prima dell'introduzione dei moduli nativi) veniva usato per creare membri privati e interfacce pubbliche. È la base per la creazione di codice incapsulato.
Questi pattern mi hanno aiutato a creare un codice più strutturato, scalabile e manutenibile.