DEV Community

Cover image for Prototype Pattern: clonare invece di costruire
Dev-Iadicola
Dev-Iadicola

Posted on • Originally published at iadicola.it

Prototype Pattern: clonare invece di costruire

Il problema: costruzione costosa o complessa

Hai un oggetto ReportTemplate con 30 proprieta: intestazione, font, margini, colori, header, footer, watermark, impostazioni di stampa. Crearlo da zero richiede un costruttore con decine di parametri o un builder con altrettante chiamate. Ma nella pratica, il 90% dei report parte dallo stesso template base con piccole variazioni: il report mensile e identico al settimanale tranne che per il titolo e il range di date.

Il Prototype Pattern propone un approccio diverso: invece di costruire un nuovo oggetto da zero, clona un oggetto esistente e modifica solo cio che cambia. Il clone e una copia indipendente — modificarlo non tocca l'originale.

Cos'e il Prototype Pattern: definizione formale

Il Gang of Four definisce il Prototype come un pattern creazionale che "specifica i tipi di oggetti da creare usando un'istanza prototipica, e crea nuovi oggetti copiando questo prototipo". In PHP, il meccanismo fondamentale e la keyword clone.

La struttura prevede: un'interfaccia Prototype con un metodo clone() (in PHP implicito tramite clone), un ConcretePrototype che implementa la clonazione, e un Client che clona il prototipo invece di istanziare con new.

clone e __clone in PHP

PHP offre supporto nativo per il Prototype Pattern tramite clone. Per default, clone esegue una shallow copy: copia le proprieta scalari ma non clona gli oggetti annidati — questi restano riferimenti condivisi. Per una deep copy serve implementare __clone():

  • Shallow clone: $copy = clone $original — le proprieta scalari sono copiate, gli oggetti annidati sono condivisi
  • Deep clone: nel metodo __clone() cloni manualmente gli oggetti annidati: $this->header = clone $this->header
  • Selective clone: cloni solo gli oggetti che devono essere indipendenti, condividi quelli immutabili

Esempio teorico: template di notifiche

Un sistema di notifiche ha template predefiniti: WelcomeEmail, InvoiceEmail, ReminderEmail. Ogni template ha layout, stili, header, footer, traduzioni. Invece di ricostruire tutto ogni volta:

  • Crei un TemplateRegistry che mantiene i prototipi: $registry->register('welcome', $welcomeTemplate)
  • Per ogni email, cloni il prototipo: $email = $registry->get('welcome') (internamente fa clone)
  • Personalizzi il clone: $email->setRecipient($user)->setName($user->name)
  • L'originale resta intatto per il prossimo utilizzo

Esempio teorico: configurazioni di gioco

Un gioco ha personaggi con centinaia di attributi: statistiche, inventario, abilita, aspetto. Creare un personaggio da zero e lento. Il Prototype Pattern permette di creare "archetipi" (guerriero, mago, ladro) e clonarli come punto di partenza. Il giocatore personalizza il clone senza ripartire da zero.

Lo stesso concetto si applica a qualsiasi sistema con configurazioni complesse: ambienti di deploy (staging clonato da production con URL diverso), configurazioni di test (setup base clonato con variazioni per ogni test), documenti (contratto standard clonato e personalizzato per ogni cliente).

Prototype vs Builder vs Factory

  • Factory: crea oggetti nuovi da zero. Il client chiede "dammi un oggetto" e la factory lo costruisce.
  • Builder: costruisce oggetti complessi passo per passo. Il client guida la costruzione.
  • Prototype: duplica un oggetto esistente. Il client parte da una copia e la modifica.

Il Prototype brilla quando la costruzione e costosa (molte proprieta, calcoli, query) e la variazione e minima (il 90% delle proprieta resta uguale). Se ogni oggetto e completamente diverso, il Prototype non offre vantaggi.

Quando usare il Prototype

  • Usa il Prototype quando la creazione di un oggetto e significativamente più costosa della sua clonazione
  • Usa il Prototype quando il sistema lavora con variazioni minime di un oggetto base
  • Usa il Prototype quando vuoi evitare una gerarchia di factory parallela alla gerarchia dei prodotti
  • Non usare il Prototype se l'oggetto ha riferimenti circolari: il deep clone diventa un incubo
  • Non usare il Prototype se ogni istanza e completamente diversa: clonare e poi sovrascrivere tutto e peggio che costruire da zero

Il Prototype Pattern e il pattern dell'efficienza pragmatica: non reinventare cio che esiste già. In PHP, con il supporto nativo di clone e __clone(), e uno dei pattern più semplici da implementare e più utili da avere nel toolkit.


👉 Leggi l'articolo completo su iadicola.it

Top comments (0)