Tutti gli approfondimenti
Engineering

Design pattern: quelli che contano davvero (con esempi in Java)

Non i 23 pattern della Gang of Four recitati a memoria: i cinque che usiamo davvero in produzione, esempi in Java, quando un pattern è la scelta sbagliata, e perché i colloqui li chiedono ancora.

Michele Cimmino · CEO & Academy Director, Lasting Dynamics · 25 agosto 2026 · 6 min read

I design pattern hanno un problema di reputazione, e se lo sono meritato: generazioni di sviluppatori li hanno imparati come un catechismo — 23 nomi della Gang of Four da recitare al colloquio — e poi applicati a caso, producendo AbstractSingletonProxyFactoryBean e altre creature che nessuno voleva. In Lasting Dynamics i pattern li usiamo tutti i giorni e li insegniamo nella nostra academy, ma li insegniamo per quello che sono: vocabolario per problemi ricorrenti, non punti da collezionare.

Questa guida è la versione pratica: i pattern che usiamo davvero, esempi in Java, e — altrettanto importante — quando applicarne uno è l'errore.

Cosa sono davvero i design pattern

Un design pattern è una soluzione con un nome a un problema di progettazione che si ripresenta. Il valore non è la soluzione (che spesso è ovvia una volta vista): è il nome condiviso. Quando in review qualcuno dice "qui farei uno Strategy", il team trasferisce in tre parole un intero disegno. I pattern sono compressione di comunicazione prima che tecnica.

Corollario onesto: un pattern applicato dove il problema non esiste non è architettura — è costo. La domanda giusta non è mai "che pattern posso usare qui?" ma "che problema ho, e ha già un nome?".

I cinque che usiamo davvero

1. Strategy — quando l'algoritmo deve poter cambiare

Il pattern più utile in assoluto, e il più semplice: incapsula comportamenti intercambiabili dietro un'interfaccia.

interface PricingStrategy {
    BigDecimal price(Order order);
}

class StandardPricing implements PricingStrategy { /* ... */ }
class BlackFridayPricing implements PricingStrategy { /* ... */ }

class Checkout {
    private final PricingStrategy pricing;
    Checkout(PricingStrategy pricing) { this.pricing = pricing; }
}

Ogni if (tipo == X) ... else if (tipo == Y) che cresce a ogni sprint è uno Strategy che chiede di nascere. In Java moderno spesso basta una lambda o un Function<Order, BigDecimal> — il pattern è l'idea, non la gerarchia di classi.

2. Factory Method — quando la creazione è una decisione

Se costruire un oggetto richiede logica (quale implementazione? con quali dipendenze?), quella logica merita un posto solo:

class NotifierFactory {
    Notifier forChannel(Channel c) {
        return switch (c) {
            case EMAIL -> new EmailNotifier(smtp);
            case SMS   -> new SmsNotifier(twilio);
            case PUSH  -> new PushNotifier(fcm);
        };
    }
}

Il beneficio vero: il codice cliente dipende da Notifier, mai dai concreti. È il fratello operativo della dependency inversion di cui parliamo nella guida alla clean architecture.

3. Observer — quando qualcosa succede e altri devono saperlo

Eventi di dominio: l'ordine è confermato, e magazzino, email e analytics devono reagire — senza che Order conosca nessuno dei tre. In Java lo incontri più spesso tramite listener, eventi Spring o un message broker che come implementazione manuale, ma il disegno è lo stesso: chi emette non conosce chi ascolta. È il pattern che tiene basso l'accoppiamento nei sistemi che crescono.

4. Adapter — quando il mondo esterno non parla la tua lingua

Ogni integrazione seria ne ha uno: la libreria di pagamento ha la sua API, il tuo dominio ha la sua interfaccia, l'adapter traduce. Il valore strategico è il confine: quando il provider cambia API (lo farà), riscrivi l'adapter, non il dominio.

5. Decorator — quando aggiungi responsabilità senza toccare la classe

Logging, caching, retry attorno a un servizio esistente:

class CachedCatalog implements Catalog {
    private final Catalog inner;
    private final Map<String, Product> cache = new ConcurrentHashMap<>();

    public Product byId(String id) {
        return cache.computeIfAbsent(id, inner::byId);
    }
}

Stessa interfaccia, comportamento arricchito, componibile a piacere. (È anche il disegno dietro mezzo ecosistema Java, dagli stream I/O ai middleware.)

Il pattern di cui diffidare: Singleton

Lo citiamo perché ai colloqui lo chiedono ancora: il Singleton garantisce una sola istanza globale. In pratica, nel 2026, è quasi sempre un segnale d'allarme — stato globale mascherato, test difficili, dipendenze nascoste. Se serve un'istanza sola, la crea il container di dependency injection (Spring lo fa di default, con scope singleton gestito, che è tutt'altra cosa). Saperlo spiegare a un colloquio vale più che saperlo implementare.

Quando un pattern è la scelta sbagliata

La regola che diamo in academy: prima il problema, poi il pattern — mai il contrario.

  • Se il codice è più semplice senza il pattern, il pattern ha torto. Tre implementazioni di PricingStrategy di cui due vuote sono un if travestito.
  • I pattern si estraggono, non si anticipano: il momento giusto per lo Strategy è la seconda variante reale, non la prima immaginata.
  • Se non sai spiegare quale cambiamento futuro il pattern protegge, stai facendo cerimonia.

E una nota per l'era degli agenti AI: strumenti come Claude Code generano pattern con entusiasmo — chiedigli una factory e ne avrai una bellissima, che serva o no. Il giudizio su se serve resta tuo. È lo stesso principio della guida al vibe coding: l'AI riempie la struttura; decidere la struttura è il mestiere.

Perché i colloqui li chiedono ancora (e come rispondere)

Perché sono un proxy rapido del vocabolario di progettazione. La risposta che colpisce non è l'elenco dei 23: è "qui userei uno Strategy perché questo if cresce a ogni sprint, e non userei un Singleton perché...". Il perché è il segnale; il nome è solo l'etichetta.

È esattamente come li alleniamo nella Lasting Dynamics Academy: i design pattern sono nel curriculum accanto ad architetture, RDBMS e testing, applicati su task reali e discussi nella review settimanale col mentore — dove "che pattern hai usato e perché" è una domanda vera, ogni settimana. Gratuita, full remote, a numero chiuso, con un'offerta di lavoro per chi completa. Se vuoi che il tuo vocabolario di progettazione diventi giudizio, le candidature sono aperte.

Domande frequenti

Devo impararli tutti e 23? No. Impara bene i cinque qui sopra più un paio che il tuo stack usa davvero (in Java: Builder e Template Method si incontrano spesso). Gli altri riconoscili quando li vedi; nessuno li usa tutti.

I design pattern valgono ancora con i linguaggi moderni? Sì, ma molti si sono dissolti nel linguaggio: lambda al posto di Strategy formali, Optional al posto di Null Object, record per i value object. Il problema che il pattern risolveva esiste ancora; la soluzione è solo diventata più leggera. Riconoscere il problema resta la competenza.

Design pattern e architettura sono la stessa cosa? Scale diverse dello stesso istinto: i pattern organizzano classi e oggetti, l'architettura organizza moduli e confini. Un sistema può avere pattern perfetti e architettura pessima — e viceversa. Servono entrambi, ed è il motivo per cui in academy si studiano insieme.