2013-03-17 12 views
5

Przechodziłem przez książkę Efektywna Java i tworzyłem notatki dla mojego przyszłego odniesienia, natknąłem się na wzorzec Konstruktora.Wzorzec konstruktora: który wariant jest preferowany?

Cóż, zrozumiałem, co to jest i jak powinno się go używać. W procesie stworzyłem dwie przykładowe odmiany wzorca budowniczego.

Potrzebuję pomocy w wyliczaniu różnic i ich zaletach? Cóż, z pewnością zauważyłem, że Example 1 udostępnia mniej metod, mniej restrykcyjnych i bardziej ogólnych, dzięki czemu można je bardziej elastycznie wykorzystywać.

Proszę wskazać inne rzeczy, które przeoczyłem?

Przykład 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(); 

    } 
} 

Przykład 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

Poważnie dół głosowania bez pozostawienie komentarzy jest lame – Sudhakar

+2

Chłopaki, jeśli można zostawić komentarz, dlaczego to pytanie jest nieodpowiednie, to naprawdę mi pomóc i inni – Sudhakar

+0

Należy przejść za pośrednictwem tej strony http: // pl .wikipedia.org/wiki/Builder_pattern # Java, aby zobaczyć odpowiedni przykład implementacji 'Pattern Buildera'. –

Odpowiedz

5

Żadne z powyższych.

Pierwsza z nich nie pozwala na zbudowanie niezmiennego Pojazdu, dlatego często używa się wzorca Konstruktora.

Drugi przykład jest wariantem pierwszego, który umożliwia uzyskanie informacji od konstruktora przy użyciu dodatkowych metod gettera. Ale te metody nie są używane nigdzie, z wyjątkiem konstruktora pojazdu, który ma bezpośredni dostęp do pól budowniczych. Nie widzę sensu w ich dodawaniu.

widzę dwie ważniejsze rzeczy do poprawy:

  1. Dwa rodzaje budowniczy zrobić dokładnie to samo. Nie ma potrzeby stosowania dwóch rodzajów. Pojedynczy jest wystarczający.
  2. Co należy zrobić, aby metoda createVehicle() została wykonana przez konstruktora budującego. Jeśli skonstruujesz CarBuilder, to oczywiście zbudujesz samochód, więc typ pojazdu powinien zostać ustawiony zaraz po zbudowaniu budowniczego. Oto, jak to napisać:

.

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

Dzięki za wskazanie "niezmienności", myślę, że to było źle. Myślałem, że wzorzec budowniczego jest głównie używany do ukrywania kroków związanych z budową złożonych obiektów, ale niezmienność nie jest wymogiem obowiązkowym. Doceniam, wysłałeś z example.cheers – Sudhakar

+0

JB Nizet: więc jeśli wprowadzę "final" do zmiennych instancji w "Przykładzie 1", to zrobi on prawidłowy BuilderPattern, prawda? – Sudhakar

+0

Jeśli pola będą ostateczne, nie będą się już kompilować, ponieważ próbujesz zmodyfikować wartość pól z kreatora. Twoi budowniczowie * są * przykładami wzorca budowniczego. Ale pierwszy nie pozwala na niezmienność i ma nadmiarowy kod, a drugi ma również nadmiarowy kod. Oba mogą być ulepszone za pomocą kodu, który pokazałem w mojej odpowiedzi, który jest bardziej zwięzły, bezpieczniejszy i pozwala na niezmienność. –

2

Jest jeszcze trzeci wariant też mniej kodu:

zamiast własną instancję pola budowniczych może również zmutować stan Vehicle. Klasy wewnętrzne można pisać prywatne członków ich zewnętrznej Klasa:

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

Od pola są prywatne i umożliwienia mu się zbudować tylko raz (building flag), zbudowany Vehicle instancje są nadal niezmienne konsumentom nawet chociaż pola nie mogą już być final (nie więcej niż realio-trulio immutability, see Eric's blog article, który jest na C#, ale koncepcje są podobne).

Musisz być ostrożniejszy, ponieważ nieokreślone pola nie muszą być inicjowane podczas budowy obiektu (wymuszane przez kompilator) i musisz dokładnie sprawdzić stan building. Jednak zapisujesz pełną dodatkową kopię wszystkich pól instancji. Zasadniczo jest to użyteczne, jeśli masz dość duży zestaw zmiennych instancji, które są zbudowane przy użyciu niewielu metod, gdzie każda metoda tworzy kilka pól naraz.

Wiem, że to nie wskazuje na jakiekolwiek zalety lub wady Waszych podejść. Jednak to podejście może zaoszczędzić dużo dodatkowego kodu, jeśli nie potrzebujesz tych pól, aby uzyskać final.

+0

Nie, wystąpienia 'Vechicle' nie są niezmienne; zobacz tę odpowiedź: http://stackoverflow.com/a/6388762/262683 –

+0

@CostiCiudatu Dzięki za wskazanie; W pierwszym przykładzie pominąłem flagę "budynku" (nie doceniając jej znaczenia). Zmieniono moją odpowiedź. –

Powiązane problemy