PDA

View Full Version : [Java Pattern Creator] Pattern Builder


e-commerce84
16-05-2010, 16:01
Ciao,
faccio riferimento a queste slide: http://www.informatica.uniroma2.it/upload/2009/IS/07-Pattern%20GOF.pdf

In particolare mi riferisco a pagina 23: Pattern Builder, mi potete dire se ho capito bene per favore?

Uso il pattern Builder quando ho un problema di costruzione complesso e voglio separare la logica algoritmica dalla costruzione dei singoli oggetti.

Nell'esempio ho le seguenti classi:

APPLICAZIONE PRINCIPALE:

/* Applicazione principale */

public class MainApp {
public static void main(){

Director director = new Director(); // Costruzione dell'oggetto director
Builder b1 = new ConcreteBuilder1(); // Costruzione del Builder Concreto di tipo 1
Builder b2= new ConcreteBuilder2(); // Costruzione del Builder Concreto di tipo 2

/* Creo il prodotto 1 di tipo 1: passa il builder di tipo effettivo ConcreteBuilder1 al metodo
* construct di director che invoca i metodi buildPartA e buildPartB del builder ti tipo 1 */
director.construct(b1);

Product p1 = b1.getResult(); // Mette il riferimento all'oggetto creato in p1
p1.show(); // Mostra il contenuto della variabile di istanza di p1

/* Creo il prodotto 2 di tipo 2: passa il builder di tipo effettivo ConcreteBuilder1 al metodo
* construct di director che invoca i metodi buildPartA e buildPartB del builder ti tipo 2 */
director.construct(b2);

Product p2 = b2.getResult(); // Mette il riferimento all'oggetto creato in p2
p2.show(); // Mostra il contenuto della variabile di istanza di p1

}

}


Classe Product:

/* Definisce il tipo Product che rappresenta un prodotto */

class Product {

ArrayList parts = new ArrayList(); // che tipo è ArrayList...booo

/* Interfaccia della classe */

/* Aggiunge una stringa all'array */
public void add(String part){
parts.add(part);
}

/* Mostra il contenuto della variabile di istanza parts */
public void show(){
foreach(string part in parts)
System.out.println(part);
}

}


DIRECTOR:

/* Classe Director */

class Director {

/* Metodo che prende come parametro di input un oggetto builder concreto */
public void construct(Builder builder){
builder.buildPartA(); // Costruisce la parte A invocando il metodo del corretto builder concreto
builder.buildPartB(); // Costruisce la parte B invocando il metodo del corretto builder concreto
}

}


Classe astratta Builder ed implementazione dei Builder concreti:


/* Builder astratto */

public abstract class Builder {
public abstract void buildPartA(); // Costruisce la parta A
public abstract void buildPartB(); // Costruisce la parta B
public abstract Product getResult(); // Restituisce il Product risultante
}

/* Builder concreto 1 */

class ConcreteBuilder1 extends Builder {

private Product product = new Product(); // Crea una nuova istanza private di Product

public void buildPartA(){ // Costruisce la parte A
/* Mette la stringa "Part A" nella prima locazione dell'array parts relativo all'oggetto di
* istanza product */
product.add("Part A");
}

public void buildPartB(){ // Costruisce la parte B
/* Mette la stringa "Part B" nella prima locazione dell'array parts relativo all'oggetto di
* istanza product */
product.add("Part B");
}

public Product getResult(){
return product; // Ritorna al chiamante l'oggetto così creato
}
}

/* Builder concreto 2 */

class ConcreteBuilder2 extends Builder{

private Product product = new Product(); // Crea una nuova istanza private di Product

public void buildPartA(){ // Costruisce la parte A
/* Mette la stringa "Part X" nella prima locazione dell'array parts relativo all'oggetto di
* istanza product */
product.add("Part X");
}

public void buildPartB(){ // Costruisce la parte B
/* Mette la stringa "Part Y" nella prima locazione dell'array parts relativo all'oggetto di
* istanza product */
product.add("Part Y");
}

public Product getResult(){
return product; // Ritorna al chiamante l'oggetto così creato
}
}


Io l'ho capito così (anche se mi sembra un bel po' macchinoso come pattern e stento a vederne una reale comodità...ma booo...forse mi sfugge qualcosa):

La classe Product mi rappresenta il mio prodotto che è formato di fatto da un array di stringhe chiamato parts. Tale classe permette di aggiungere una stringa all'array e di visualizzarne il contenuto

La classe astratta Builder rappresenta un generico oggetto costruttore ed ha 3 metodi abstract: buildPartA (che costruisce la parte A dell'oggetto finale), buildPartB (che costruisce la parte B dell'oggetto finale) e getResult() che ritorna il riferimento al prodotto costruito. Vabbè...poteva usare un'interface al posto della classe abstract mi sà...giusto?

Poi estendo tale classe con 2 sottoclassi ConcreteBuilder1 e ConcreteBuilder2 che di fatto implementano in modo diverso la costruzione di un oggetto Product (il primo builder costruisce l'oggetto inserento la stringa "Part A" nella prima locazione dell'array e "Part B" nella seconda. Mentre il secondo Builder ci mette dentro le stringhe "Part X" e "Part Y")

La classe Director serve a creare un oggetto director che conterrà la logica di costruzione del prodotto (cioè nella costruzione di un Product:prima fai la parte A e poi fai la parte B).
Tale oggetto conterrà solo un metodo che prenderà come parametro di input il riferimento ad un builder concreto (che nel nostro caso sarà o ConcreteBuilder1 o ConcreteBuilder2).
In base al tipo effettivo del parametro richiamerà i corretti metodi buildPartA e buildPartB su tale parametro)

In pratica quindi succede ciò. Voglio creare un oggetto e posso crearlo in 2 modi differenti che chiamiamo MODO 1 e MODO 2 che creeranno 2 diversi tipi di prodotto PRODOTTO 1 e PRODOTTO 2.

Nell'applicazione principale (classe [MainApp]) per prima cosa creo un oggetto director che appunto contiene la logica di creazione (prima parte A e poi parte B).

Poi creo due builder concreti b1 e b2 di tipo rispettivamenteConcreteBuilder1 e ConcreteBuilder2.

Ora voglio creare un particolare prodotto col MODO 1, come faccio?

beh ho già creato il director, ho già creato il builder concreto di tipo 1, quindi alla riga:
director.construct(b1);[/b1] invoco il metoto construct dell'oggetto director passandogli come parametro il builder concreto di tipo 1, questo a sua volta invocherà i metodi concreti buildPartA e buildPartB relativi proprio alla classe con il tipo concreto del builder (quindi i metodi implementati in ConcreteBuilder1), quest'ultimo costruisce l'oggetto richiesto.

e poi con la riga: [code]Product p2 = b2.getResult(); metto il riferimento dell'oggetto appena costruito nella variabile p2.

mmm...è così che funziona? cmq mi pare parecchio cervellotica la cosa...in quali casi può tornare utile?

Grazie