7

I was going through Effective Java book , and creating notes for my future reference , i came across Builder Pattern.

Well i understood what it is and how its suppose to be used.In the process i created a two example variations of the builder pattern.

I would need help in listing down the differences and the advantage each has? Well i certainly noticed that , Example 1 exposes less methods , there by less restrictive and more generic , there by allowing it to be used more flexibly.

Please point out other things i have missed?

Example 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();

    }
}

Example 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();
    }
}
Sudhakar
  • 4,823
  • 2
  • 35
  • 42
  • 8
    Seriously down voting without leaving comments is lame – Sudhakar Mar 17 '13 at 13:14
  • 3
    Guys , if you could leave comments as to why this question is inappropriate , it would really help me and the others – Sudhakar Mar 17 '13 at 13:23
  • You should go through this site http://en.wikipedia.org/wiki/Builder_pattern#Java to see the appropriate example for `Builder Pattern` implementation. – Vishal K Mar 17 '13 at 13:40

2 Answers2

9

None of the above.

The first one doesn't allow building an immutable Vehicle, which is often why the Builder pattern is used.

The second example is a variation of the first one which allows getting information from the builder using additional getter methods. But those those methods aren't used anywhere, except in the Vehicle constructor, which has access to the builder fields directly. I don't see the point in adding them.

I see two more important things to improve:

  1. The two builder types do exactly the same thing. There's no need for two types. A single one is sufficient.
  2. What the createVehicle() method does should be done by the builder constructor. If you construct a CarBuilder, it's obviously to build a car, so the type of the vehicle should be set as soon as the builder is constructed. Here's how I would write it:

.

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();
    }
}
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Thanks for pointing out 'immutability', i guess thats were i got it wrong.I thought the builder pattern is predominately used to hide steps involving construction of complex objects , but immutability is not a mandatory requirement. Appreciate ,you posted with an example.cheers – Sudhakar Mar 17 '13 at 13:54
  • JB Nizet:so if i introduce 'final' to the instance variables in `Example 1` , then it will make a valid BuilderPattern , right ? – Sudhakar Mar 17 '13 at 14:04
  • If you make the fields final, it won't compile anymore, since you're trying to modify the value of the fields from the builder. Your builders *are* examples of the Builder pattern. But the first one doesn't allow immutability and has redundant code, and the second one has redundant code as well. They can both be improved by using the code I showed in my answer, which is more concise, safer and allows for immutability. – JB Nizet Mar 17 '13 at 14:09
  • Well , in your example 'wheels' variable in Builder is still mutable.So this allows the builder instance to be reused , Ofcourse with this it produces a new Vehicle instance and not in anyway affects the Vehicle created earlier. But is this still Ok ?Could you clarify ? Is builder re-usability correct practice ? – Sudhakar Mar 17 '13 at 14:55
  • The point of the builder pattern is to construct an immutable Vehicle. The Builder of course have to be mutable, else we would be back to square one. And immutability doesn't mean that an object can't be reused. It means that its state is known and fixed at construction time and never changes after. Re-read the chapter about immutability in Effective Java. If you don't want the builder to be reused, then set a flag when the build() method has been called, and throw an exception if it's called again. But this has nothing to do with immutability. – JB Nizet Mar 17 '13 at 15:00
3

There is a third variant too, with less code:

Instead of having their own instance fields the builders could also mutate the state of Vehicle. Inner classes can write private members of their outer class:

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

Since the fields are private and you allow it to be build only once (building flag), built Vehicle instances are still immutable to consumers even though the fields cannot be final anymore (no more realio-trulio immutability, see Eric's blog article which is on C# but the concepts are similar).

You need to be more careful as non-final fields do not have to be initialized during object construction (enforced by the compiler) and you must check the building state carefully. You do however save a full extra-copy of all instance fields. In general, this is useful if you have a rather large set of instance variables that are built with rather few methods, where each method builds a few fields at once.

I know this does not point out any advantages or drawbacks of your approaches. However, this approach can save a lot of extra code if you do not need the fields to be final.

Matthias Meid
  • 12,455
  • 7
  • 45
  • 79
  • No, the `Vechicle` instances are not immutable; see this answer: http://stackoverflow.com/a/6388762/262683 – Costi Ciudatu Mar 17 '13 at 13:43
  • @CostiCiudatu Thanks for pointing out; I omitted the `building` flag in my initial example (underestimating its importance). Edited my answer. – Matthias Meid Mar 17 '13 at 14:09
  • Thanks for this answer because it is a learning scenario. I see people often doing a Builder pattern like this without a separate Builder class that allows getting the immutable copy. So, this is a common variation on Builder that I see people use. I personally don't like it. It basically means that after you have the built copy, you can still call `.build` method on it over and over. So illogical. – djangofan Jun 11 '20 at 17:02