2013-03-17 2 views
5

Я проходил через эффективную книгу Java и создавал заметки для моей будущей ссылки, Я столкнулся с шаблоном Builder.Builder Выкройка: какой вариант является предпочтительным?

Ну, я понял, что это такое и как его предполагается использовать. В этом процессе я создал два примера вариантов шаблона построителя.

Мне нужна помощь в перечислении различий и преимуществ каждого из них? Ну, конечно, я заметил, что Example 1 предоставляет меньше методов, там менее ограничительные и более общие, там, позволяя использовать его более гибко.

Укажите, что я пропустил?

Пример 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(); 

    } 
} 

Пример 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

Серьезно вниз голосования, не оставляя комментарии хромает – Sudhakar

+2

Ребята, если вы можете оставить комментарии, почему этот вопрос неуместно, это действительно помогло бы мне и другие – Sudhakar

+0

Вы должны пройти через этот сайт HTTP: // ан .wikipedia.org/wiki/Builder_pattern # Java, чтобы увидеть соответствующий пример для реализации «Builder Pattern». –

ответ

5

Ничего из перечисленного.

Первый не позволяет создать неизменяемое транспортное средство, поэтому часто используется шаблон Builder.

Второй пример - это вариант первого варианта, который позволяет получать информацию от строителя с использованием дополнительных методов получения. Но эти методы не используются нигде, кроме конструктора Vehicle, который имеет доступ к полям строителя напрямую. Я не вижу смысла добавлять их.

Я вижу две более важные вещи, чтобы улучшить:

  1. Два типа строителя делают ровно то же самое. Нет необходимости в двух типах. Достаточно одного.
  2. Что делает метод createVehicle() конструктором-конструктором. Если вы строите CarBuilder, очевидно, что нужно построить автомобиль, поэтому тип транспортного средства должен быть установлен, как только строитель будет построен. Вот как я бы это написал:

.

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

Спасибо, что указали на «неизменность», я думаю, что это было неправильно. Я думал, что шаблон строителя преимущественно используется для скрытия шагов, связанных с построением сложных объектов, но неизменяемость не является обязательным требованием. Цените, вы отправили с example.cheers – Sudhakar

+0

JB Nizet: так, если я введу «final» в переменные экземпляра в «Пример 1», тогда он сделает действительный BuilderPattern, правильно? – Sudhakar

+0

Если вы сделаете поля окончательными, они больше не будут компилироваться, так как вы пытаетесь изменить значение полей из построителя. Ваши строители * являются примерами шаблона Builder. Но первый не позволяет неизменности и имеет избыточный код, а второй - избыточный код. Их можно улучшить, используя код, который я показал в своем ответе, который является более кратким, безопасным и позволяет неизменность. –

2

Существует третий вариант тоже, с меньшим количеством кода:

вместо того, чтобы их собственный экземпляр поля строителей также может мутировать состояние Vehicle. Внутренние классы могут писать частные член их внешнего класс:

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

Поскольку поля являются частным и вы позволяете ему быть только строить разы (building флага), построенный Vehicle экземпляров все еще неизменны потребителей даже хотя поля не могут быть final больше (не более realio-trulio immutability, see Eric's blog article, который находится на C#, но концепции похожи).

Вы должны быть более осторожны, так как нестрочные поля не обязательно должны быть инициализированы при построении объекта (соблюдаемые компилятором), и вы должны тщательно проверить состояние building. Однако вы сохраняете полную дополнительную копию всех полей экземпляра. В общем, это полезно, если у вас есть довольно большой набор переменных экземпляра, которые построены с использованием нескольких методов, где каждый метод создает сразу несколько полей.

Я знаю, что это не указывает на какие-либо преимущества или недостатки ваших подходов. Однако этот подход может сэкономить много дополнительного кода, если вам не нужны поля final.

+0

Нет, экземпляры 'Vechicle' не являются неизменяемыми; см. этот ответ: http://stackoverflow.com/a/6388762/262683 –

+0

@CostiCiudatu Спасибо за указание; Я опустил флаг «building» в моем первоначальном примере (недооценивая его важность). Отредактировал мой ответ. –

Смежные вопросы