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
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