Il pattern Factory - Libero.it• Il pattern FACTORY è un pattern di tipo “Creazionale” secondo...

Post on 21-Aug-2020

2 views 0 download

Transcript of Il pattern Factory - Libero.it• Il pattern FACTORY è un pattern di tipo “Creazionale” secondo...

Il pattern Factory

• Il pattern FACTORY è un pattern di tipo “Creazionale” secondo la classificazione della GoF

• I pattern di tipo creazionali si occupano della costruzione degli oggetti e delle problematiche che si possono originare, astraggono il processo di creazione degli oggetti, nascondono i dettagli della creazione e rendono i sistemi indipendenti da come gli oggetti sono creati e composti

• Il pattern Factory incapsula la creazione concreta degli oggetti, consentendo al client (l’utilizzatore) di non conoscere i dettagli

• “Definisce una interfaccia per la creazione degli oggetti, consentendo alle sottoclassi di stabilire quale classe istanziare” (GoF)

UTILIZZO del pattern FACTORYQuando si ha la necessità di costruire un oggetto, si dovrebbe

invocare il giusto costruttore con i giusti argomenti. Può capitare che all’atto della costruzione non si conosca o si

voglia ignorare le caratteristiche dell’oggetto da istanziare (e quindi quale tipo di oggetto)

Esempio: costruzione di una classe per produrre messaggi di log

public enum LogLevel{ ERROR, INFO, TRACE, DEBUG } public interface Logger { void setLogLevel(LogLevel level) {this.logLevel=level; }

void trace( String message ); void info( String message ); void debug(String message)void error( String message ); LogLevel logLevel;}

Un logger può scrivere i propri messaggi su un file o sulla consolle, o anche in un database

public class FileLogger implements Logger { public FileLogger() throws java.io.IOException {

pw = new java.io.PrintWriter(new java.io.FileWriter( "c:\trace.log" ));

} public void debug( String message ) {

if (logLevel>=DEBUG)pw.println( "DEBUG: " + message ); pw.flush(); }

public void error( String message ) {if (logLevel>=ERROR)pw.println( "ERROR: " + message ); pw.flush();

} . . . }

Versione console

public class SystemLog implements Logger {public void debug( String message ) {

if (logLevel>=DEBUG) System.out.println("DEBUG:"+message ); }

public void error( String message ) { if (logLevel>=ERROR)System.out.println("ERROR: "+message);

} …

}

• Per usare l’una o l’altra classe si devono costruire gli oggetti opportuni

// ... SystemLogger log = new SystemLogger(); // ... log.debug( “PRIMO MESSAGGIO"); // ... • Se si utilizza una factory si può cambiare

agevolmente il logger utilizzato, senza dover modificare codice esistente!

FACTORY

public class LoggerFactory { public static Logger getLogger() { return new SystemTrace(); }

} • Utilizzo

Logger log = new LoggerFactory.getLogger(); //... log.debug(“PRIMO MESSAGGIO"); // ...

Nel Facory Method si può centralizzare il meccanismo di scelta del logger opportuno, si possono realizzare alternative, ecc.

public class LoggerFactory { public static Logger getLogger() { try { return new FileLogger(); } catch (java.io.IOException ex ) { Logger t = new SystemLogger();

t.error( "could not instantiate FileLogger: " + ex.getMessage() ); return t; }

} }

FACTORY METHOD

Il pattern FACTOR METHOD si può usare sia quando effettivamente può non essere noto alla classe utilizzatore quale tipo di oggetto dover utilizzare, oppure anche quando questo è noto, ma potrà essere modificato in futuro.

• Il client è liberato dalla necessità di conoscere l’oggetto istanziato, il pattern FACTORY METHOD restituisce una classe astratta, e si realizza attraverso più classi ereditate dalla classe astratta

La creazione del sottotipo, da parte delle factory, può anche essere guidata dal client(Il client sa quale tipo oggetto richiedere, ma vuole ignorare i dettagli di costruzione)

ESEMPIOinterface Cane { public void abbaia(); } Class chihuaha implements Cane {

public void abbaia() { System.out.println(“au au au! (sono un chihuaha)"); } }

class rottweiler implements Cane { public void abbaia() {

System.out.println("WOU WAO! (SONO UN ROTTWEILER"); } }

class pastoretedesco implements Cane { public void abbaia() { System.out.println(“wauu wauu!(sono un Pastore Tedesco)”); } }

class CaneFactory { public static Cane getCane(String stazza) { if ( stazza.equals(“piccola") )

return new chihuaha(); else if ( stazza.equals(“grossa") )

return new Rottweiler(); else if ( stazza.equals(“media") )

return new pastoretedesco(); return null; } }

• Come si vede il client comunica un criterio di scelta alla classe FACTORY, questa interpreta il criterio ed effettua la scelta

• La classe client riceve una istanza della classe senza dover conoscere quale sia esattamente la classe richiesta

I pattern FACTORY e ITERATOR

• IL pattern ITERATOR serve ad accedere agli elementi di una collezione sequenzialmente

• Il metodo iterator() è classificabile come FACTORY METHOD pattern, perché il metodo iterator() solleva il suo chiamante dalla necessità di conoscere quale classe sia realmente istanziata.

Pattern FACTORY: Sintesi

Il problema affrontatoIl Factory Method pattern si applica quando:• Una classe non può conoscere in anticipo

quale oggetto deve creare per i suoi scopi• Una classe, pur conoscendo il tipo di oggetto

di cui ha bisogno, preferisce delegare la creazione dell’oggetto a un prestatore di servizi

Diagramma

Partecipanti• Product definisce l’interfaccia per il tipo di oggetto creato dal

Factory method• ConcreteProduct: Implementa l’interfaccia Product• Creator: dichiara il Factory Method, che restituisce un

oggetto di tipo Product• ConcreteCreator: Specifica il Factory Method per restituire

l’istanza di ConcreteProduct opportuna

Collaborazioni• Creator si avvale delle sue sottoclassi per implementare il

factory method in modo da restituire l’istanza di ConcreteProduct appropriata

• “Factory Method Pattern” consente alle sottoclassi di decidere quali classe istanziare, non vuol dire che la scelta è fatta a run time dalle sottoclassi, ma vuol dire che la creazione concreta è fatta dall’opportuno concreteCreator utilizzato dalla classe client utilizzatrice.

ConseguenzeBenefici• Il codice è più flessibile e riusabile senza

l’onere di dover istanziare ed utilizzare specifiche classi. Utilizzando l’interfaccia Product può lavorare con qualsiasi ConcreteProduct (anche future estensioni)

Svantaggi• L’uso estensivo del Factory Method implica un

aumento del numero di classi. Per ogni particolare Product si dovrebbe creare la super classe opportuna.

Dettagli di implementazione• Creator può essere astratta o anche concreta

e produrre una versione default del Factory Method.

• Una Factory può essere usata anche per creare più tipi di prodotti (attraverso un parametro e istruzioni if…then…else)

IMPLEMENTAZIONI TIPICHE: FRAMEWORK (es logger, tipi di documenti) Il pattern Factory si presenta spessissimo nelle

librerie di classi Java

Il pattern Factory: Connessione di gerarchie di classi

• (GOF) Supponiamo di avere delle figure che possono essere monificate col mouse (allungate, stiracchiate,…). E’ preferibile separare le informazioni relative alla manipolazione dalla figura stessa, attraverso delle classe specifiche.

Il FACTORY method è “createManipulator”, le figure concrete specializzano la costruzione del manipulator opportuno. In questo modo le gerarchie di classi sono parallelizzate, e il punto di contatto si realizza proprio col Factory method (dove è racchiusa la conoscenza di quale classe dell’altra gerarchia è necessaria)

Altri pattern creazionaliABSTRACT FACTORY Costruire una famiglia di oggetti che

condividono una o piu’ caratteristiche

BUILDER Raccogliere le informazioni di un oggetto prima della sua effettiva costruzione

PROTOTYPE Ottenere le caratteristiche di un oggetto da costruire tramite un esempio

MEMENTO Ricostruire un oggetto a partire da una versione “dormiente” o da una descrizione dello stato dell’oggetto

SINGLETON Assicurare che di un oggetto ne venga creata un’unica istanza