2013-03-17 20 views
5

Stavo passando per un libro di Java efficace e la creazione di note per il mio riferimento futuro, mi sono imbattuto in Pattern Builder.Schema costruttore: quale variante è preferibile?

Bene, ho capito cosa è e come deve essere utilizzato. Nel processo ho creato due varianti di esempio del modello di builder.

Avrei bisogno di aiuto per elencare le differenze e il vantaggio che ciascuno ha? Beh, certamente ho notato che, Example 1 espone meno metodi, lì con meno restrittiva e più generico, permettendo di utilizzarlo in modo più flessibile.

Si prega di indicare altre cose che ho perso?

Esempio 1

package item2; 

/** 
* @author Sudhakar Duraiswamy 
* 
*/ 
public class Vehicle { 

    private String type; 
    private int wheels; 

    interface Builder<T>{ 
     public T build(); 
    } 

    public static class CarBuilder implements Builder<Vehicle>{ 
     private String type; 
     private int wheels;  

     CarBuilder createVehicle(){ 
      this.type= "Car"; 
      return this; 
     } 

     CarBuilder addWheels(int wheels){ 
      this.wheels = wheels; 
      return this; 
     } 

     public Vehicle build(){ 
      Vehicle v = new Vehicle(); 
      v.type = type; 
      v.wheels = wheels; 
      return v; 
     }    
    } 

    public static class TruckBuilder implements Builder<Vehicle>{  
     private String type; 
     private int wheels; 

     TruckBuilder createVehicle(){   
      this.type= "Truck"; 
      return this; 
     } 

     TruckBuilder addWheels(int wheels){ 
      this.wheels = wheels; 
      return this; 
     } 

     public Vehicle build(){ 
      Vehicle v = new Vehicle(); 
      v.type = type; 
      v.wheels = wheels; 
      return v; 
     } 
    } 

    public Vehicle(){ 

    } 

    public static void main(String[] args) { 
     //This builds a car with 4 wheels 
     Vehicle car = new Vehicle.CarBuilder().createVehicle().addWheels(4).build(); 

     //THis builds a Truck with 10 wheels 
     Vehicle truck = new Vehicle.TruckBuilder().createVehicle().addWheels(10).build(); 

    } 
} 

Esempio 2

package item2; 
/** 
* @author Sudhakar Duraiswamy 
* 
*/ 
public class Vehicle2 { 

    private String type; 
    private int wheels; 

    interface Builder<T>{ 
     public T build();  
     public String getType(); 
     public int getWheels() ; 
    } 

    public static class CarBuilder implements Builder<Vehicle2>{ 
     private String type; 
     private int wheels;  

     public String getType() { 
      return type; 
     } 
     public int getWheels() { 
      return wheels; 
     } 

     CarBuilder createVehicle(){ 
      this.type= "Car"; 
      return this; 
     } 

     CarBuilder addWheels(int wheels){ 
      this.wheels = wheels; 
      return this; 
     } 

     public Vehicle2 build(){   
      return new Vehicle2(this); 
     }    
    } 

    public static class TruckBuilder implements Builder<Vehicle2>{  
     private String type; 
     private int wheels; 

     public String getType() { 
      return type; 
     } 

     public int getWheels() { 
      return wheels; 
     } 

     TruckBuilder createVehicle(){   
      this.type= "Truck"; 
      return this; 
     } 

     TruckBuilder addWheels(int wheels){ 
      this.wheels = wheels; 
      return this; 
     } 

     public Vehicle2 build(){ 
      return new Vehicle2(this); 
     } 
    } 


public Vehicle2(Builder<? extends Vehicle2> builder){ 
    Vehicle2 v = new Vehicle2(); 
    v.type = builder.getType(); 
    v.wheels = builder.getWheels(); 
} 

    public Vehicle2(){ 
    } 

    public static void main(String[] args) {    
     //This builds a car with 4 wheels 
     Vehicle2 car = new Vehicle2.CarBuilder().createVehicle().addWheels(4).build(); 

     //THis builds a Truck with 10 wheels 
     Vehicle2 truck = new Vehicle2.TruckBuilder().createVehicle().addWheels(10).build(); 
    } 
} 
+7

Scherzi giù di voto senza osservazioni che lasciano è zoppo – Sudhakar

+2

Ragazzi, se si potesse lasciare commenti sul motivo per cui questa domanda è inadeguato, sarebbe davvero mi aiuta e gli altri – Sudhakar

+0

Si dovrebbe passare attraverso questo sito http: // it .wikipedia.org/wiki/Builder_pattern # Java per vedere l'esempio appropriato per l'implementazione 'Builder Pattern'. –

risposta

5

Nessuna delle precedenti.

Il primo non consente la costruzione di un Veicolo immutabile, che è spesso il motivo per cui viene utilizzato il modello di Builder.

Il secondo esempio è una variante del primo che consente di ottenere informazioni dal generatore utilizzando metodi getter aggiuntivi. Ma quei metodi non sono usati ovunque, tranne nel costruttore di veicoli, che ha accesso diretto ai campi del costruttore. Non vedo il punto di aggiungerli.

vedo due cose più importanti da migliorare:

  1. I due tipi costruttore fanno esattamente la stessa cosa. Non c'è bisogno di due tipi. Uno solo è sufficiente.
  2. Il metodo createVehicle() deve essere eseguito dal costruttore costruttore. Se costruisci un CarBuilder, è ovviamente necessario costruire un'auto, quindi il tipo di veicolo deve essere impostato non appena viene costruito il costruttore. Ecco come lo scriverei:

.

public final class Vehicle { 

    private final String type; 
    private final int wheels; 

    private Vehicle(Builder builder) { 
     this.type = builder.type; 
     this.wheels = builder.wheels; 
    } 

    public static Builder carBuilder() { 
     return new Builder("car"); 
    } 

    public static Builder truckBuilder() { 
     return new Builder("truck"); 
    } 

    public static class Builder { 
     private final String type; 
     private int wheels; 

     private Builder(String type) { 
      this.type = type; 
     } 

     public Builder addWheels(int wheels){ 
      this.wheels = wheels; 
      return this; 
     } 

     public Vehicle build() { 
      return new Vehicle(this); 
     }    
    } 

    public static void main(String[] args) { 
     Vehicle car = Vehicle.carBuilder().addWheels(4).build(); 
     Vehicle truck = Vehicle.truckBuilder().addWheels(10).build(); 
    } 
} 
+0

Grazie per aver sottolineato "l'immutabilità", immagino che fosse sbagliato. Ho pensato che il pattern del builder fosse usato principalmente per nascondere passaggi che implicano la costruzione di oggetti complessi, ma l'immutabilità non è un requisito obbligatorio. Apprezzo, hai postato con un example.cheers – Sudhakar

+0

JB Nizet: quindi se introduco 'final' alle variabili di istanza in 'Esempio 1', allora creerà un BuilderPattern valido, giusto? – Sudhakar

+0

Se si rendono finali i campi, non verrà più compilato, poiché si sta tentando di modificare il valore dei campi dal builder. I tuoi costruttori * sono * esempi del modello di Builder. Ma il primo non consente l'immutabilità e ha codice ridondante, e il secondo ha anche un codice ridondante. Possono entrambi essere migliorati usando il codice che ho mostrato nella mia risposta, che è più conciso, più sicuro e consente l'immutabilità. –

2

C'è una terza variante anche, con meno codice:

Invece di avere il proprio esempio i campi costruttori potrebbe anche mutare lo stato di Vehicle. classi interne possono scrivere membri privati ​​della loro classe esterna:

class Vehicle { 
    private int wheels; 

    private Vehicle() {} 

    public static class Builder { 
    private boolean building = true; 
    private Vehicle vehicle = new Vehicle(); 

    public Builder buildWheels(int wheels) { 
     if(!this.building) throw new IllegalStateException(); 
     this.vehicle.wheels = wheels; 
     return this; 
    } 

    public Vehicle build() { 
     this.building = false; 
     return this.vehicle; 
    } 
    } 
} 

Dal momento che i campi sono private e si permettono di essere costruire solo volta (building bandiera), costruito Vehicle casi sono ancora immutabili ai consumatori anche sebbene i campi non possano essere più final (non più realio-trulio immutability, see Eric's blog article che si trova su C# ma i concetti sono simili).

È necessario prestare maggiore attenzione poiché i campi non finali non devono essere inizializzati durante la costruzione di oggetti (applicati dal compilatore) ed è necessario verificare attentamente lo stato building. Tuttavia, si salva una copia extra completa di tutti i campi di istanza. In generale, questo è utile se si dispone di un insieme piuttosto ampio di variabili di istanza create con pochi metodi, in cui ogni metodo crea pochi campi contemporaneamente.

So che questo non evidenzia alcun vantaggio o svantaggio dei vostri approcci. Tuttavia, questo approccio consente di risparmiare molto codice aggiuntivo se non si desidera che i campi siano final.

+0

No, le istanze di 'Vechicle' non sono immutabili; guarda questa risposta: http://stackoverflow.com/a/6388762/262683 –

+0

@CostiCiudatu Grazie per la segnalazione; Ho omesso la flag 'building' nel mio esempio iniziale (sottostimando la sua importanza). Modificato la mia risposta. –

Problemi correlati