Builder Pattern: which variant is preferred? [closed]

匆匆过客 提交于 2019-11-30 14:25:08

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

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!