Parlami del design pattern che hai usato nel tuo sviluppo.
sobes.tech AI
Risposta dell'AI
Ho utilizzato i seguenti pattern di progettazione:
-
MVC (Model-View-Controller): Separazione della logica dell'applicazione. Il modello gestisce i dati, la vista si occupa della visualizzazione e il controller gestisce l'interazione dell'utente e aggiorna il modello o la vista. Applicato in Angular, dove i componenti implementano parzialmente questa ideologia.
-
MVVM (Model-View-ViewModel): Simile a MVC, ma introduce il ViewModel come intermediario tra la vista e il modello. Il ViewModel contiene la logica di business per la visualizzazione dei dati e l'elaborazione delle azioni dell'utente. Usato attivamente con React e Vuex (Vue), dove lo stato dell'applicazione è gestito centralmente.
// Esempio di reattività in React con useState import React, { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); // useState parte del meccanismo MVVM const increment = () => { setCount(count + 1); // Aggiornamento dello stato tramite setter }; return ( <div> <p>Count: {count}</p> {/* Visualizzazione dello stato */} <button onClick={increment}>Increment</button> {/* Azione che influisce sullo stato */} </div> ); } -
Pattern component: Suddivide l'interfaccia utente in componenti indipendenti e riutilizzabili. Ogni componente incapsula la propria logica, markup e stili. È alla base dei framework moderni come React, Vue e Angular.
// Esempio di componente React semplice function Button(props) { return ( <button className="my-button" onClick={props.onClick}> {props.label} </button> ); } -
Adapter (Adattatore): Trasforma l'interfaccia di una classe in un'altra che i clienti si aspettano. Permette di far lavorare classi con interfacce incompatibili insieme. Usato per integrare librerie di terze parti o API con firme di metodi diverse.
// Esempio di adattatore per lavorare con diversi client API class OldApi { getDataOld(id) { console.log(`Recupero dati da Old API per id ${id}`); return { id: id, name: `Item ${id}` }; } } class NewApi { fetchDataNew(itemId) { console.log(`Recupero dati da New API per id ${itemId}`); return { itemId: itemId, label: `Prodotto ${itemId}` }; } } class ApiAdapter { constructor(apiClient) { this.apiClient = apiClient; } getData(id) { if (this.apiClient instanceof OldApi) { return this.apiClient.getDataOld(id); } else if (this.apiClient instanceof NewApi) { const newData = this.apiClient.fetchDataNew(id); return { id: newData.itemId, name: newData.label }; } throw new Error("Client API non supportato"); } } const oldApiAdapter = new ApiAdapter(new OldApi()); console.log(oldApiAdapter.getData(1)); const newApiAdapter = new ApiAdapter(new NewApi()); console.log(newApiAdapter.getData(2)); -
Iteratore (Iterator): Fornisce un modo per accedere sequenzialmente agli elementi di un oggetto composito senza rivelarne la rappresentazione interna. Usato nei cicli (
for...of) e nei metodi degli array (forEach,map,filter).// Esempio di utilizzo di un iteratore in JavaScript const numbers = [1, 2, 3, 4, 5]; const iterator = numbers[Symbol.iterator](); console.log(iterator.next()); // { value: 1, done: false } console.log(iterator.next()); // { value: 2, done: false } // ... console.log(iterator.next()); // { value: undefined, done: true } for (const number of numbers) { console.log(number); } -
Decoratore (Decorator): Aggiunge dinamicamente nuove responsabilità a un oggetto, consentendo di estenderne le funzionalità senza modificare la sua struttura. Usato come HOC (Higher-Order Components) in React o decoratori in Angular/TypeScript.
// Esempio di Higher-Order Component (HOC) in React function withLogging(WrappedComponent) { return function WithLogging(props) { console.log(`Component ${WrappedComponent.name} renderizzato con props:`, props); return <WrappedComponent {...props} />; }; } // Applicazione dell'HOC const EnhancedButton = withLogging(Button); // Uso del componente migliorato // <EnhancedButton label="Clicca" onClick={() => console.log('Cliccato!')} /> -
Singleton (Omino): Garantisce che una classe abbia una sola istanza e fornisce un punto di accesso globale ad essa. Usato per gestire lo stato globale dell'app o per creare un'istanza unica di un servizio (ad esempio, servizio di logging, configurazione).
// Esempio di pattern Singleton class ConfigManager { constructor() { if (ConfigManager.instance) { return ConfigManager.instance; } this.settings = {}; // Inizializza le impostazioni ConfigManager.instance = this; } setSetting(key, value) { this.settings[key] = value; } getSetting(key) { return this.settings[key]; } } const config1 = new ConfigManager(); const config2 = new ConfigManager(); console.log(config1 === config2); // true (stessa istanza) config1.setSetting('apiUrl', 'https://api.example.com'); console.log(config2.getSetting('apiUrl')); // https://api.example.com -
Metodo Factory (Factory Method): Definisce l'interfaccia per creare un oggetto, ma lascia alle sottoclassi decidere quale classe istanziare. Usato per creare diversi tipi di elementi dell'interfaccia utente o oggetti basati sulla configurazione.
-
Strategia (Strategy): Definisce una famiglia di algoritmi, incapsula ciascuno di essi e li rende intercambiabili. Permette di variare l'algoritmo indipendentemente dai clienti che lo utilizzano. Usato per implementare diversi approcci di ordinamento dei dati, validazione dei form o gestione degli eventi.
L'uso di questi pattern ha aiutato a creare un codice più strutturato, modulare, testabile e manutenibile.