Sobes.tech
Middle+

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.