【问题标题】:Builder pattern. Initialization of duplicate parameters?生成器模式。重复参数的初始化?
【发布时间】:2020-12-13 09:02:12
【问题描述】:

假设我有一个汽车制造商,其参数包括型号、颜色和速度:

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

有没有提供这个的模板?

【问题讨论】:

    标签: java builder-pattern


    【解决方案1】:

    这是一个常见问题。本质上,您需要公开一个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;
    

    【讨论】:

      【解决方案2】:

      initFrom(Car) 方法添加到您的Builder 类中,该方法从给定的Car 实例中调用所有getter,并使用返回值初始化其参数。以后调用Builder 的方法可能会用当时正确的值覆盖这些值。

      接下来,您可以将TemplateCar 类作为新的父类引入Car,它允许使用不完整的参数集进行构建,并且具有自己的Builder(当然,那么您需要更改上面提到的方法initFrom(TemplateCar))。

      这是您要求“模板”时的意思吗?

      【讨论】:

        【解决方案3】:

        感谢您的回答!我决定采用@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);
        }
        

        YourCustomBuilderCar.java

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

        客户端代码: 汽车 car1 = new Car.Builder() .initFrom(new YourCustomBuilderCar()) .速度(200) .build();

        【讨论】:

          猜你喜欢
          • 2020-06-16
          • 2015-09-25
          • 2016-04-25
          • 2017-10-18
          • 2015-07-01
          • 2016-06-23
          • 1970-01-01
          • 2014-11-03
          • 2022-01-19
          相关资源
          最近更新 更多