Il design pattern prototype è uno dei pattern creazionali fondamentali introdotti dalla Gang of Four e permette di creare nuovi oggetti clonando un oggetto iniziale, detto appunto prototipo.
A differenza di altri pattern come Abstract factory o Factory permette di specificare nuovi oggetti a tempo d’esecuzione (run-time), utilizzando una PrototypeFactory per salvare e reperire dinamicamente le istanze degli oggetti desiderati.
Questo pattern può rivelarsi utile quando:
le classi da istanziare sono specificate solamente a tempo d'esecuzione, per cui un codice statico non può occuparsi della creazione dell’oggetto;
quando ==le istanze di una classe possono avere soltanto un limitato numero di stati==, per cui può essere più conveniente clonare al bisogno il prototipo corrispondente piuttosto che creare l’oggetto e configurarlo ogni volta.
I vantaggi nel suo utilizzo sono i seguenti:
Indipendenza dal metodo d’instanziazione: analogamente ai pattern Abstract factory e Builder, Prototype permette di incapsulare al suo interno la modalità di istanziazione degli oggetti, liberando i Client dalla necessità di conoscere i nomi delle classi da instanziare.
Modularità a run-time: l’aggiunta di un prodotto richiede semplicemente la **registrazione dell’oggetto da clonare alla PrototypeFactory.
Definire nuovi oggetti modificando valori: Quando si devono definire numerosi oggetti differenziati tra loro solo dai valori che assumono le loro variabili interne è più comodo istanziare nuovi oggetti semplicemente clonando un prototipo iniziale e successivamente impostare la rappresentazione interna perché assuma la configurazione desiderata.
Minore necessità di sottoclassi: Il pattern Prototype permette di risolvere un problema di Factory relativo alla dimensione della gerarchia di classi necessarie: usando un metodo factory è necessario creare sottoclassi per inserire un nuovo prodotto e, se si hanno numerosi prodotti molto simili tra di loro, la definizione di una nuova classe per ognuno può portare a grandi quantità di codice duplicato.
La difficoltà principale nell’utilizzo del pattern è l’implementazione del metodo Clone in quanto deve comportarsi come una copia in profondità (deep copy): la copia di un oggetto composto implichi la copia delle sue sottoparti.
Title
In .NET il pattern è disponibile utilizzando l’interfaccia ICloneable.
Implementazione
Questo pattern è formato dai seguenti oggetti:
Prototype: Definisce un’interfaccia per clonare sé stesso.
ConcretePrototype: Le sottoclassi ConcretePrototype implementano l’interfaccia di Prototype, fornendo un’operazione per clonare sé stessi.
Client: crea un nuovo oggetto del tipo desiderato chiedendo a un prototipo di clonarsi, ovvero invocando il metodo clone definito da ConcretePrototype.
Ho creato l’interfaccia IPrototype che eredita da ICloneable con i suoi prototype concreti e la classe factory.
Chiamiamo ora il pattern dall’esterno:
Che mostra questo:
Creo il prototype Foo: Name: Foo Name - Status: Foo Status - Guid: fb61fb21-4cea-45d0-ab2e-c0c1fc5e843e
A partire dal clone dello standard ci cambio nome (e guid): Name: NewName - Status: Foo Status - Guid: 327baa46-e4a8-4a25-8203-675a5834
2ca0
Creo il prototype Bar: Name: Bar Name - Status: Bar Status - Guid: 82a20aa0-71d8-423c-a8ee-8f16a8316cd0
Creo un secondo prototype Bar clonando il primo: Name: Bar Name - Status: Bar Status - Guid: 05b09aa8-990d-4d69-820d-6585f85944d6