Java Design Pattern: Factory Pattern



Continuando il discorso sui design pattern iniziato precedentemente, andiamo oggi a vedere un altro pattern molto utilizzato: il Factory Method Pattern.

Il GoF (Gang of Four Design Patterns) lo definisce così:

Definisce un’interfaccia per creare oggetti, ma lascia alle sottoclassi la
decisione del tipo di classe a istanziare.

Già dalla definizione, si può notare come il problema riguardante la parentela tra classi discusso per il Singleton non sia più presente. Infatti, si decide di ricorrere al Factory Method Pattern nel momento in cui non siamo in grado di conoscere a priori il tipo esatto dell'oggetto da creare oppure quando si vuole delegare ad altre entità il compito della creazione degli oggetti.

Consultando gran parte della letteratura, il pattern viene rappresentato con un diagramma UML simile a questo:

Factory Method Pattern

Elementi fondamentali del pattern

  • Creator: ha il compito di dichiarare la Factory che si occuperà poi di restituire l'oggetto appropriato;
  • ConcreteCreator: effettua l'override del metodo di Factory al fine di restituire l'implementazione adeguata dell'oggetto;
  • Product: definisce l'interfaccia dell'oggetto che Factory deve ritornare;
  • ConcreteProduct: implementa l'oggetto in base a Product;

La prima osservazione, se pur banale che va fatta è che l'implementazione è nettamente più complessa rispetto a quella quasi elementare del Singleton.

Qualche esempio

Partendo da un esempio piuttosto elementare, andiamo a definire una CatFactory:

//Product
interface Cat{
public void speak ();
}

Ogni elemento restituito dalla factory dovrà implementare questa interfaccia.

Andiamo ora a creare le classi concrete:

//ConcreteProduct
class Abissino implements Cat{
public void speak(){
System.out.println("Abissino");
}
}
class AmericanCurl implements Cat{
public void speak(){
System.out.println("American Curl");
}
}
class Asian implements Cat{
public void speak(){
System.out.println("Asian");
}
}

Ho deciso di implementare tutte le classi in maniera non pubblica, ipotizzandone il posizionamento in uno stesso file. Infatti, come sappiamo, Java vieta più di una classe pubblica in uno stesso file, in virtù del fatto che il file deve avere lo stesso nome della classe pubblica.

Il concetto fondamentale di questo pattern è proprio il fatto che ogni classe concreta sia un derivato di un tipo base. In questo caso specifico, ogni classe implementa Cat.

La classe Factory

L'elemento a cui è demandata la creazione degli oggetti è proprio la cosiddetta classe Factory, che avrà un metodo statico con al suo interno questa funzionalità.

Vediamo un'ipotetica struttura:

public class Factory{
public static Cat generateCat(String criteria){
if(criteria.equals("Abissino"))
return new Abissino();
if(criteria.equals("Curl"))
return new AmericanCurl();
if(criteria.equals("Asian"))
return new Asian();
return null;
}
}

Notiamo che al momento il codice della classe Factory è relativamente semplice, perchè accetta solo tre stringhe. In un'ipotetica situazione reale, il codice sarebbe ben più lungo e complesso ma questo è sufficiente a dare un'idea su come il pattern funzioni.

Il Factory Method Pattern presenta diversi vantaggi e svantaggi, tra cui:

  • rappresenta un collegamento alle sottoclassi: tramite il creator è possibile scegliere dinamicamente quale classe concreta utilizzare senza alcun impatto sull'utilizzo dell'utente finale;
  • collega gerarchie di classi parallelamente: i ConcreteCreator possono collegarsi con i ConcreteProduct e generare un collegamento parallelo tra gerarchie diverse;

Perchè utilizzare il Factory Method Pattern?

Come detto in precedenza, ci sono diversi casi in cui non possiamo conoscere a priori quale sarà il tipo concreto degli oggetti che verranno istanziati. In realtà la questione è ben più ampia.

Si potrebbe incorrere in casi nei quali conosciamo il tipo esatto degli oggetti, ma quest'ultimo potrà cambiare in futuro. Segue che il client sia libero dall'onere di conscere che tipo di oggetti istanziare e il pattern restituisce un oggetto astratto che si realizza poi mediante le classi ereditate dall'entità astratta. Spesso il client guida la creazione dell'oggetto, come nell'esempio mostrato prima, ma ignora i dettagli della sua costruzione.

Il pattern Iterator

Per quanto possa sembrare strano, il pattern Iterator è assimilabile alla famiglia dei Factory Method. Infatti Iterator ci da la possibilità di accedere sequanzialmente agli elementi di una lista, sollevando il chiamante dalla necessità di conoscere quali siano le classi istanziate.

Iterator è un'interfaccia che mette a disposizione tre metodi:

  • boolean hasNext() che restituisce true se e solo se è ancora possibile effettuare un'iterazione;
  • Object next() che restituisce l'elemento successivo a quello corrente;
  • void remove() che si occupa di rimuovere l'elemento corrente dalla lista;

Vediamo un esempio:

import java.io.*; 
import java.util.*; 
class Test { 
public static void main(String[] args) 
{ 
ArrayList
 list = new ArrayList
(); 
list.add("1"); 
list.add("2"); 
list.add("3"); 
list.add("4"); 
list.add("5"); 
// Iterator per attraversare la lista  
Iterator iterator = list.iterator(); 
System.out.println("List elements : "); 
while (iterator.hasNext()) 
System.out.print(iterator.next() + " "); 
System.out.println(); 
} 
} 


Otterremo come output:

List elements : A B C D E

Java mette a disposizione una classe ListIterator che permette di attraversare le collezioni di oggetti in entrambe le direzioni, quindi da testa a coda e da coda a testa.

Sintesi

Utilizziamo il Factory Method Pattern quando:

  • Una classe non può conoscere in anticipo il tipo esatto degli oggetti da creare;
  • La classe conosce il tipo esatto degli oggetti, ma ha bisogno di delegare ad un'entità esterna la loro creazione;

Partecipanti:

  • Product:  è l'interfaccia dell'oggetto creato dal Factory Method;
  • ConcreteProduct: implementa Product;
  • Creator: dichiara il Factory Method e restituisce un oggetto di tipo Product;
  • ConcreteCreator: specifica il Factory Method e restituisce l'istanza corretta;

Segue che:

  • Il codice ha un livello di flessibilità e riusabilità più alto;
  • Un uso inappropriato può portare alla generazione di troppe classi;

Ponendo l'attenzione su alcuni dettagli implementativi:

  • Creator può essere concreta o astratta, e creare una versione di default del Factory Method;
  • Una Factory può costruire oggetti di tipo diverso mediante istruzioni di tipo if-then-else;

Tipicamente viene utilizzato per Logger e applicativi di questo genere.

 
 
 
 
 

Articoli correlati

    Java algoritmi di ordinamento: Bubble Sort

    Programmando, nasce spesso la necessità di ordinare le collezioni di dati o oggetti che devono poi essere manipolate. Ordinare una lista può essere utile nei casi in cui si debbano…

    Java Design Pattern: Prototype Pattern

    Andremo ora a parlare di un pattern creazionale che ci permette di "copiare con classe". Sì, anche se sembra strano, il compito fondamentale di questo pattern è copiare. Sto parlando…

    Java Design Pattern: Builder Pattern

    Andiamo oggi a parlare di un pattern creazionale che in molte situazioni può rappresentare una valida alternativa alla costruzione di oggetti mediante costruttori: il Builder Pattern. La necessità di introdurre meccanismi…

    Java Design Pattern: Strategy Pattern

    Uno dei pattern che gode di una notevole popolarità ed è al contempo piuttosto semplice è lo Strategy Pattern. Membro della famiglia dei pattern comportamentali, ha il compito di gestire algoritmi,…

    Java: Introduzione ai design pattern: Singleton

    Chiunque abbia anche una minima esperienza di programmazione, si sarà reso conto di come i problemi sianoricorrenti. Infatti troviamo spesso problemi con uno stesso pattern ma con contesti differenti. Ad esempio, un…

    Java 12, finalmente meno prolisso?

    Conosciamo tutti Java per le sue caratteristiche grazie alle quali, nonostante siano passati più di 20 anni dalla prima versione,è tutt'oggi uno dei linguaggi più studiati e più utilizzati, malgrado…

    JQuery morirà nel 2019?

    Per un po' di tempo, la centralità di JQuery è stata oggetto di dibattito tra gli sviluppatori web. Come programmatori web interessati a Javascript, eravamo curiosi di sapere che opinioni…

    45 utili siti che avresti voluto conoscere prima

    In rete sono presenti talmente tanti siti web dedicati alla sviluppo web e alla grafica, che risulta molto complicato conoscerli tutti. Oggi, vi proponiamo una lista di siti web non…

    30 Manuali di riferimento per JavaScript: jQuery, Node.js, React

    Questa lista ha lo scopo di introdurre i nuovi sviluppatori a JavaScript (jQuery, Node.js e React) e agevolare il compito degli sviluppatori più esperti. jQuery jQuery API (Official) Leggi → jQuery Cheatsheet (Devhints) Leggi → jQuery Cheat Sheet (JavaScript Toolbox) Leggi…

    Le migliori librerie JavaScript del 2018

    Dal momento che Javascript si è rivelato il linguaggio di programmazione più popolare e ampiamente utilizzato nel 2018, l'ecosistema che si sviluppa intorno ad esso sta cominciando a diventare importante. JavaScript…

    Convertire il testo in voce e viceversa con Javascript: tutorial+codice

    In questo tutorial sperimenteremo la Web Speech API: un'interfaccia browser molto potente che consente di registrare la voce umana e convertirla in testo. La useremo anche per fare il contrario: interpretare…

    I 5 Migliori Frameworks JavaScript per Applicazioni Desktop

    Non molto tempo fa era impossibile costruire un'applicazione desktop con JavaScript. Fortunatamente, questi tempi sono passati, e ora gli sviluppatori JS possono utilizzare le loro conoscenze e competenze di sviluppo…