Шаблон строителя. Инициализация повторяющихся параметров?

Предположим, у меня есть сборщик автомобилей с такими параметрами, как модель, цвет и скорость:

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

А я строю машины вот так:

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

Как видите, у меня есть параметры, которые приходится постоянно дублировать. Хотелось бы иметь возможность строить новые машины на основе некоторых существующих заготовок типа этой:

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

Есть ли какой-либо шаблон, который предусматривает это?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
571
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Добавьте метод initFrom(Car) в свой Builder класс, который вызывает все геттеры из данного экземпляра Car и инициализирует его параметры возвращаемыми значениями. Последующие вызовы методов Builder могут перезаписать эти значения правильными на тот момент значениями.

В качестве следующего вы можете ввести класс TemplateCar в качестве нового родительского класса для Car, который позволяет выполнять сборку с неполным набором параметров и имеет свой собственный Builder (конечно, тогда вам нужно изменить вышеупомянутый метод на initFrom(TemplateCar)).

Это то, что вы имели в виду, когда просили «Шаблон»?

Это распространенная проблема. По сути, вам нужно разоблачить asBuilder(). Этот метод экземпляра получает построитель, который инициализируется значениями переданного экземпляра.

Car existingCar = Car.builder()......build() ;

//new car with same props as existing but the speed
Car existingCarButFaster = existingCar.asBuilder()
                           .speed(existingCar.speed * 2)
                           .build();

Реализация asBuilder() должна быть простой.

Кроме того, вы, кажется, генерируете много шаблонов. Если подключение кодовой базы к генератору кода для вас не проблема, вы можете использовать библиотеку Lombok, которая используется в подавляющем большинстве проектов.

    /**
     * If true, generate an instance method to obtain a builder that is initialized with the values of this instance
     * Legal only if {@code @Builder} is used on a constructor, on the type itself, or on a static method that returns
     * an instance of the declaring type.
     * 
     * @return Whether to generate a {@code toBuilder()} method.
     */
    boolean toBuilder() default false;
Ответ принят как подходящий

Спасибо за ответы! Я решил использовать решение @tquadrat, но немного расширить его. Я решил добавить интерфейс для классов, которые инициализируют сборщики.

Автомобиль.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);
}

ВашCustomBuilderCar.java

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

Код клиента: Автомобиль car1 = новый Car.Builder() .initFrom(новый ВашCustomBuilderCar()) .скорость(200) .строить();

Другие вопросы по теме