Organizzare il codice ci salverà da un sacco di dolore. Usando le caratteristiche della programmazione orientata agli oggetti, possiamo impiegare certi design pattern per ottenere una migliore leggibilità, ridurre la ridondanza e creare astrazioni, se necessario. Uno di questi pattern è il factory pattern.
Il factory pattern è un tipo di pattern Object Oriented che segue la metodologia DRY. Come suggerisce il nome, le istanze dell’oggetto sono create usando una fabbrica per creare l’oggetto richiesto per noi.
Diamo un’occhiata ad un esempio molto semplice di utilizzo del pattern factory per assemblare un oggetto alligator
. Per farlo, dobbiamo prima creare delle fabbriche che creino le parti alligator
per noi:
class TailFactory { constructor(props) { this.tailLength = props.tailLength; }};class TorsoFactory { constructor(props) { this.color = props.color; }};class HeadFactory { constructor(props) { this.snoutLenth = props.snoutLenth; }};
Ora, creiamo una classe che funga da intermediario tra le classi delle fabbriche reali e l’utente. Chiamiamola ReptilePartFactory
:
class ReptilePartFactory { constructor(type, props) { if(type === "tail") return new TailFactory(props); if(type === "torso") return new TorsoFactory(props); if(type === "head") return new HeadFactory(props); }};
Andiamo avanti e assembliamo l’alligatore vero e proprio ora e usiamo la ReptilePartFactory
per ottenere le parti necessarie per noi:
let alligator = {};let alligatorProps = { tailLength : 2.5, color: "green", snoutLenth: 1};//gets a tail from the tail factoryalligator.tail = new ReptilePartFactory("tail", alligatorProps); //gets a torso from the torso factoryalligator.torso = new ReptilePartFactory("torso", alligatorProps);//gets a head from the head factoryalligator.head = new ReptilePartFactory("head", alligatorProps);
Guardando il modello sopra, sembra che potremmo usare la stessa ReptilePartFactory
per creare parti per oggetti simili all’alligatore. Le fabbriche in background non dovrebbero mai conoscere la natura dell’oggetto finale.
Quindi, usare il pattern factory ci dà alcuni vantaggi:
- Creazione dinamica di oggetti: Può essere usato nei casi in cui il tipo dell’oggetto viene deciso a runtime.
- Astrazione: L’utente non deve mai accedere realmente al costruttore dell’oggetto reale.
- Riusabilità/Manutenzione: Le stesse fabbriche possono essere usate per oggetti simili e ci permette di aggiungere/rimuovere facilmente nuove classi di oggetti senza cambiare molto codice.
Ora che abbiamo un po’ di comprensione del factory pattern, esploriamo un po’ come scrivere un codice factory pattern migliore.
L’esempio sopra usa un if-ladder per trovare quale fabbrica chiamare in base all’input dell’utente. Questa è un’implementazione semplice, intuitiva e non molto aperta ai cambiamenti. Se abbiamo nuove parti da aggiungere in seguito, allora dovremmo disturbare il ReptilePartFactory
. Questa è una violazione dei principi SOLID, che afferma “Le entità software (classi, moduli, funzioni, ecc.) dovrebbero essere aperte per l’estensione, ma chiuse per la modifica”.
Come possiamo memorizzare le classi factory in un oggetto e chiamare il part factory richiesto usando la parte che vogliamo come chiave? Prima dovremmo registrare le fabbriche, sarebbe semplice come:
let registeredPartFactories = {};registeredPartFactories = class TailFactory{ ...};registeredPartFactories = class TorsoFactory { ...};registeredPartFactories = class HeadFactory { ...};
E ora, il livello astratto può chiamare le fabbriche in questo modo:
class ReptilePartFactory { constructor(type, props) { return new registeredPartFactories(props); }};
Questo approccio è molto più pulito e permette di espandere le nostre fabbriche senza influenzare il codice nel ReptilePartFactory
.
In conclusione
Ci sono diversi altri pattern orientati agli oggetti che aumentano anche la leggibilità e la qualità. Quindi, prima di usare il pattern factory, controllate se c’è un reale bisogno di esso. Se avete intenzione di creare tipi simili di oggetti ripetutamente e avete anche bisogno di un livello per creare nuove istanze usando questi oggetti e fornendo un certo livello di astrazione alla logica di creazione, allora sì, il pattern factory è una buona opzione.