Builder Pattern

di il
6 risposte

Builder Pattern

Buonasera a Tutti,
premetto che sono pronto alle peggiori offese!!!

Sto cercando di mettere in pratica ciò che studio ( e cerco di assimilare ) dal libro (bibbia) "Design Pattern" della famigerata GoF!!!

Sto, nello specifico, cercando di implementare un Builder Pattern seguendo le spiegazioni ma, purtroppo sono arenato e c'è un tassello che non riesco a mettere al posto giusto ma non so quale e chiaramente come.
Bando alle ciance, ecco cosa ho combinato:

Interfaccia Builder:

public interface Builder {
	public abstract void BuildPart1(String nomeParte);
	public abstract void BuildPart2(String nomeParte);
	public abstract void BuoldPart3(String nomeParte);
	public abstract Builder getBuilder();
}
Classe Che Implementa Builder:

public class ConcreteBuilder implements Builder {

	@Override
	public void BuildPart1(String nomeParte) {
		System.out.println("La Parte"+" "+nomeParte+" "+"è stata Creata");
		
	}

	@Override
	public void BuildPart2(String nomeParte) {
		System.out.println("La Parte"+" "+nomeParte+" "+"è stata Creata");
	}

	@Override
	public void BuoldPart3(String nomeParte) {
		System.out.println("La Parte"+" "+nomeParte+" "+"è stata Creata");
	}

	@Override
	public Builder getBuilder() {
		return this;
	}
}
Classe Direttore:
Quello che vorrei è che la classe Direttore si occupi di Creare l'oggetto avvalendosi del "ConcreteBuilder" :
( Questo, sono convinto, sia l'inizio dell'errore)

public class Direttore {
	public Direttore(ConcreteBuilder concreteBuilder,String nomeParte1,String nomeParte2,String nomeParte3) {
		concreteBuilder.BuildPart1(nomeParte1);
		concreteBuilder.BuildPart2(nomeParte2);
		concreteBuilder.BuoldPart3(nomeParte3);
	}
}
Per finire, certo non in bellezza, la classe Client la quale "dovrebbe rappresentare" colui che chiede al Direttore di costruire per le l'oggetto richiesto:

public class Client {
	public static void main(String[] args) {
	ConcreteBuilder cb=new ConcreteBuilder();
	Direttore d=new Direttore(cb, "Parte1", "Parte2", "Parte3");
	cb.getBuilder();
	}
}
Detto questo...SCATENATEVI ma che siano offese costruttive !

6 Risposte

  • Re: Builder Pattern

    MarcoRayRaimondi ha scritto:


    Interfaccia Builder:
    
    public interface Builder {
    	public abstract void BuildPart1(String nomeParte);
    	public abstract void BuildPart2(String nomeParte);
    	public abstract void BuoldPart3(String nomeParte);
    	public abstract Builder getBuilder();
    }
    
    Ecco, già questo non quadra. Nella astrazione del builder (che potrebbe essere una classe astratta o una interfaccia), ci sono una serie di metodi che rappresentano gli step (i "passi") possibili per costruire un oggetto ma poi ci deve anche essere un metodo in più che serve a costruire ed ottenere l'oggetto finale. Ma questo oggetto finale NON è il Builder!
    Nell'ultimo metodo hai messo un getBuilder() che restituisce un Builder. No, non ha senso. E l'oggetto finale da dove lo tiri fuori??
  • Re: Builder Pattern

    [/code][/quote]
    Ecco, già questo non quadra. Nella astrazione del builder (che potrebbe essere una classe astratta o una interfaccia), ci sono una serie di metodi che rappresentano gli step (i "passi") possibili per costruire un oggetto ma poi ci deve anche essere un metodo in più che serve a costruire ed ottenere l'oggetto finale. Ma questo oggetto finale NON è il Builder!
    Nell'ultimo metodo hai messo un getBuilder() che restituisce un Builder. No, non ha senso. E l'oggetto finale da dove lo tiri fuori??
    [/quote]

    Ciao e grazie mille!
    Concettualmente ho capito che cosa mi stai dicendo ma praticamente non sono riuscito a metterlo all'opera.

    Quello che cerco di capire è:
    Un Builder è ad esempio:
    
    public class Libro{
    Srting titolo,codiceIbs,autore;
    double prezzo;
    
    public static Libro Builder(){
    private static String titolo;
    private static String codiceIbs;
    private static String autore;
    private static double prezzo;
    public static Build(){
    Libro libro=new Libro();
    libro.titolo=titolo;
    libro.codiceIbs=codiceIbs;
    libro.autore=autore;
    libro.prezzo=prezzo;
    return libro;
    }
    public Builder(String codiceIbs){
    Builder.codiceIbs=codiceIbs;
    }
    public Builder titolo(String titolo){
    this.titolo=titolo;
    return this;
    }
    ...
    ...
    
    Ora quello che però non riesco a mettere in pratica è:
    Se volessi implementare una maniera di costruire un costruttore che si "adatti" a qualsia oggetto?
    Cioè, riprendendo la "vecchia Interfaccia":
    
    public interface Builder{
    public void BuildPart1();
    public void BuildPart2();
    public void BuildPart3();
    public void Build();//?????
    }
    
    Non capisco come fare...potreste farmi vedere un accenno di codice?
    Grazie!
  • Re: Builder Pattern

    MarcoRayRaimondi ha scritto:


    Un Builder è ad esempio:
    
    public class Libro{
    Srting titolo,codiceIbs,autore;
    double prezzo;
    
    public static Libro Builder(){
    private static String titolo;
    private static String codiceIbs;
    private static String autore;
    private static double prezzo;
    public static Build(){
    Libro libro=new Libro();
    libro.titolo=titolo;
    libro.codiceIbs=codiceIbs;
    libro.autore=autore;
    libro.prezzo=prezzo;
    return libro;
    }
    public Builder(String codiceIbs){
    Builder.codiceIbs=codiceIbs;
    }
    public Builder titolo(String titolo){
    this.titolo=titolo;
    return this;
    }
    ...
    ...
    
    A parte il fatto che questo che hai scritto è sbagliato sintatticamente (e anche concettualmente) e non ti compila proprio. Ma questo comunque NON è il pattern Builder!! È una variante semplificata del pattern Builder che si usa sovente specialmente quando ci sono classi "immutabili" che hanno tanti attributi opzionali.

    Questa è la tipica tecnica di mettere una nested class (chiamata solitamente solo Builder) con i metodi che ritornano il builder stesso per sfruttare il method chaining e rendere la costruzione più "fluente" ma come ripeto, non è il pattern Builder come descritto nei libri sui Design Pattern. Perché astrazione/ereditarietà qui sostanzialmente non ci sono.

    MarcoRayRaimondi ha scritto:


    Se volessi implementare una maniera di costruire un costruttore che si "adatti" a qualsia oggetto?
    
    public interface Builder{
    public void BuildPart1();
    public void BuildPart2();
    public void BuildPart3();
    public void Build();//?????
    }
    
    Quello che forse non ti è ancora chiaro è che un "builder" è strettamente legato ad un certo tipo di oggetto che costruisce. Se hai una classe Pizza (magari complessa e/o immutabile) allora puoi fare un PizzaBuilder che avrà metodi es. addPomodoro(), addFormaggio() ecc... e con un build() che restituisce Pizza.

    Nella tua interfaccia hai un Builder (di che?) con metodi buildPart1(), buildPart2() (che fanno che??) e un build() (che restituisce che???)
    Non ha molto senso ..... un builder deve essere più "contestualizzato".

    Volendo astrarre il più possibile sfruttando anche i generics, la astrazione più "alta" potrebbe essere
    public interface Builder<T> {
        T build();
    }
    Sì, solo tutto qui ma perché a questo livello di astrazione si sa nulla, solo che il builder ha un build() che dà un certo oggetto.
    Poi lo si potrebbe estendere e specializzare, andando a contestualizzare meglio e fissando anche la parametrizzazione.
    public interface PizzaBuilder extends Builder<Pizza> {
        void addPomodoro();
        void addFormaggio();
           //....
    }
    E poi ci possono essere varie implementazioni concrete che variano appunto nel modo di costruire l'oggetto e/o nei dati utilizzati, es. in un PizzaNapoliBuilder il addPomodoro() potrebbe aggiungere un certo tipo di pomodoro mentre un PizzaNewYorkBuilder potrebbe fare diversamente.

    La mia conclusione è che forse non hai ancora compreso bene il pattern Builder .... o forse stai cercando di usarlo in un contesto dove invece sarebbe più utile un altro pattern "creazionale" ....
  • Re: Builder Pattern

    La mia conclusione è che forse non hai ancora compreso bene il pattern Builder .... o forse stai cercando di usarlo in un contesto dove invece sarebbe più utile un altro pattern "creazionale" ....
    Si, sicuramente non ho compreso bene il Pattern. Per questo cerco di trovare spiegazioni.
    Dunque, legandomi alla tua spegazione ho fatto questo:

    Interfaccia che mette a disposizione un metodo che dovrà creare l'oggetto:
    
    public interface Builder {
    	public void Build();
    }
    
    Specializzo l'interfaccia estendendola:
    
    public interface PizzaBuilder extends Builder {
    	public void addPomodoro();
    	public void condimento();
    	public void addFormaggio();
    	public void tipoCottura();
    }
    
    Ora, per esempio concretizzo con una classe PizzaNizzarda:
    
    public class PizzaNizzarda implements PizzaBuilder {
    	@Override
    	public void Build() {
    		new PizzaNizzarda();
    	}
    	@Override
    	public void addPomodoro() {
    		System.out.println("ExtraPomodoro");
    	}
    	@Override
    	public void addFormaggio() {
    		System.out.println("Bufala");
    	}
    	@Override
    	public void tipoCottura() {
    		System.out.println("Teglia");
    	}
    	@Override
    	public void condimento() {
    		String stringa;
    		stringa="Olive - Alici - Tonno - Mais";
    		System.out.println(stringa);	
    	}
    }
    
    Ammesso e non concesso che fino a quì sia giusto...la classe "Director" che dovrebbe occuparsi di creare realmente l'oggetto tramite il Builder come deve essere imlementata?

  • Re: Builder Pattern

    MarcoRayRaimondi ha scritto:


    Interfaccia che mette a disposizione un metodo che dovrà creare l'oggetto:
    
    public interface Builder {
    	public void Build();
    }
    
    NO. Se fai una astrazione di così "alto" livello, cioè contemplare solo il fatto che un qualunque builder ha sicuramente un metodo build, allora la devi fare come interfaccia "generica", quindi Builder<T> e il metodo build() restituisce T.
    Se metti void come tipo di ritorno del build() poi nessun sotto-tipo/implementazione lo puoi cambiare e quindi diventa di fatto tutto completamente inutile.

    MarcoRayRaimondi ha scritto:


    Specializzo l'interfaccia estendendola:
    
    public interface PizzaBuilder extends Builder {
    	public void addPomodoro();
    	public void condimento();
    	public void addFormaggio();
    	public void tipoCottura();
    }
    
    Sì, più o meno, considerando comunque quanto ho appena detto sopra.

    MarcoRayRaimondi ha scritto:


    Ora, per esempio concretizzo con una classe PizzaNizzarda:
    
    public class PizzaNizzarda implements PizzaBuilder {
    	@Override
    	public void Build() {
    		new PizzaNizzarda();
    	}
    	
    	   ......
    }
    
    NO. Perché qui stai facendo confusione tra l'oggetto builder e l'oggetto da costruire. Oltre al fatto che come dicevo prima, un build() che ha void come tipo di ritorno non ha senso. E in pratica non stai "costruendo" nulla.
  • Re: Builder Pattern

    Ciao!!
    Spero / penso di aver capito il mio errore di concetto!!!
    Dunque, volendo generalizzare ho creato questa struttura.
    Innanzi tutto ho focalizzato un prodotto "qualsiasi":
    
    public class Product {
    	private String attr1;
    	private String attr2;
    	private String attr3;
    	public void setAttr1(String attr1) {
    		this.attr1 = attr1;
    	}
    	public void setAttr2(String attr2) {
    		this.attr2 = attr2;
    	}
    	public void setAttr3(String attr3) {
    		this.attr3 = attr3;
    	}
    	
    	public String toString() {
    		return this.attr1+" "+this.attr2+" "+this.attr3;
    	}
    	
    }
    
    Ho creato la classe astratta Builder che si occuperà di costruire il prodotto e di mettere a disposizione i metodi che lo comporranno:
    
    public abstract class Builder {
    	protected Product product;
    	public Product getProduct() {
    		return product;
    	}
    	public void createNewProduct() {
    		product=new Product();
    	}
    	public abstract void buildAttr1();
    	public abstract void buildAttr2();
    	public abstract void buildAttr3();
    }
    
    Ovviamente la classe concreta che estende quella astratta builder, cioè quella che si occuperà ralmente di costruire, passo passo l'oggetto richiesto:
    
    public class ConcreteBuilder extends Builder {
    
    	@Override
    	public void buildAttr1() {
    		product.setAttr1("Attributo 1 !!");
    
    	}
    
    	@Override
    	public void buildAttr2() {
    		product.setAttr2("Attributo 2 !!");
    
    	}
    
    	@Override
    	public void buildAttr3() {
    		product.setAttr3("Attributo 3 !!");
    
    	}
    
    }
    
    La tanto rinomata classe Director, che si occuperà di interfacciarsi con il "client" , chiedere la costruzione dell'oggetto richiesto ed infine ritornarlo al cliente:
    
    public class Director {
    	private Builder builder;
    	
    	public void setBuilder(Builder nb) {
    		this.builder=nb;
    	}
    	
    	public Product getProduct() {
    		return this.builder.getProduct();
    	}
    	
    	public void costructProduct() {
    		this.builder.createNewProduct();
    		this.builder.buildAttr1();
    		this.builder.buildAttr2();
    		this.builder.buildAttr3();
    	}
    }
    
    La classe Cliente che fa concretamente la richiesta di costruzione dell'oggetto, istanziando il direttore ed il prodotto specializzato:
    
    public class Client {
    
    	public static void main(String[] args) {
    		Director director=new Director();
    		
    		Builder specializedProduct=new ConcreteBuilder();
    		
    		director.setBuilder(specializedProduct);
    		director.costructProduct();
    		
    		Product product=director.getProduct();
    		System.out.println(product.toString());
    
    	}
    
    }
    
    Che ne pensi?
    Inizio ad entrare nel concetto?
    Ciao e grazie mille!!!!
Devi accedere o registrarti per scrivere nel forum
6 risposte