Search code examples
javabuilder-pattern

Builder pattern. Initialization of duplicate parameters?


Suppose I have a car builder with parameters such as model, color and speed:

 public class Car {

    private String model;
    private int color;
    private int speed;

    public Car(String model, int color, int speed) {
        this.model = model;
        this.color = color;
        this.speed = speed;
    }

    //..Getters

    public static class Builder {
        private String model;
        private int color;
        private int speed;

        public Builder model(String model) {
            this.model = model;
            return this;
        }

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

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

        public Car build() {
            return new Car(model, color, speed);
        }
    }
}

And I build cars like this:

    Car car1 = new Car.Builder()
            .model("Audi")
            .color(Color.RED.getRGB())
            .speed(200)
            .build();
    Car car2 = new Car.Builder()
            .model("Audi")
            .color(Color.RED.getRGB())
            .speed(350)
            .build();
    Car car3 = new Car.Builder()
            .model("Audi")
            .color(Color.RED.getRGB())
            .speed(175)
            .build();

As you can see, I have parameters that have to be constantly duplicated. I would like to be able to build new cars based on some existing blanks like this:

    Car car1 = new Car.Builder()
            .initFrom(redAudi)
            .speed(200)
            .build();
    Car car2 = new Car.Builder()
            .initFrom(redAudi)
            .speed(350)
            .build();
    Car car3 = new Car.Builder()
            .initFrom(redAudi)
            .speed(175)
            .build();
}

Is there any template that provides for this?


Solution

  • Thanks for the answers! I decided to go for @tquadrat's solution, but expand on it a bit. I decided to add an interface for the classes that initialize the builders.

    Car.java

    public class Car {
    
    private final String model;
    private final int color;
    private final int speed;
    
    public Car(String model, int color, int speed) {
        this.model = model;
        this.color = color;
        this.speed = speed;
    }
    
    //..Getters
    
    public static class Builder {
        private String model;
        private int color;
        private int speed;
    
        public Builder initFrom(@NotNull CarBuilderInitializer initializer) {
            Builder builder = initializer.initBuilder(this);
            this.model = builder.getModel();
            this.color = builder.getColor();
            this.speed = builder.getSpeed();
            return this;
        }
    
        public Builder model(String model) {
            this.model = model;
            return this;
        }
    
        public Builder color(int color) {
            this.color = color;
            return this;
        }
    
        public Builder speed(int speed) {
            this.speed = speed;
            return this;
        }
    
        public Car build() {
            return new Car(model, color, speed);
        }
    }}
    

    CarBuilderInitializer.java

        public interface CarBuilderInitializer {
        Car.Builder initBuilder(Car.Builder builder);
    }
    

    YourCustomBuilderCar.java

     public class YourCustomBuilderCar implements CarBuilderInitializer {
        @Override
        public  initBuilder(@NotNull Car.Builder builder) {
            return builder
                    .model("Audi");
                    .color(Color.RED);
        }
    }
    

    Client code: Car car1 = new Car.Builder() .initFrom(new YourCustomBuilderCar()) .speed(200) .build();