Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaBuilder模式使用_Java_Design Patterns_Pojo - Fatal编程技术网

JavaBuilder模式使用

JavaBuilder模式使用,java,design-patterns,pojo,Java,Design Patterns,Pojo,最近,我看到一些开发人员使用嵌套的构建器类(如 public class User { private String firstName; private String lastName; public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = fir

最近,我看到一些开发人员使用嵌套的构建器类(如

public class User {

    private String firstName;
    private String lastName;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public static class UserBuilder {

        private String firstName;
        private String lastName;

        public User build() {
            User user = new User();
            user.firstName = firstName;
            user.lastName = lastName;
            return user;
        }

        public UserBuilder withFirstName(String firstName) {
            this.firstName = firstName;
            return this;
        }

        public UserBuilder withLastName(String lastName) {
            this.firstName = firstName;
            return this;
        }       
    }

}
现在,他们声称这使代码更具可读性。我的观点是,这有以下缺点:

  • 我不能简单地添加字段并期望IDE为我完成代码,因为现在我也需要更新这个内部类

  • 简单POJO携带与VO无关的代码

  • 如果我在这里遗漏了什么,我会寻求任何建议。请随意添加您的想法

    修改后的示例代码如下所示:

    User user = new User.UserBuilder()
                    .withFirstName("Name")
                    .withLastName("surName")
                    .build();
    

    这是约书亚·布洛赫的一篇文章。他很好地解释了为什么、何时以及如何使用建筑商:

    这是他在《有效Java》一书中的一个项目。如果您对Java有一点经验,我强烈建议您阅读本书

    要点:

    当你得到一个有很多属性的类时,有几种方法可以创建一个对象并初始化它

    如果你一个接一个地设置每一个属性,它可能会很冗长,并且你的对象在创建后可能会被改变。使用此方法,不可能使类不可变,也无法确保对象处于一致状态

    文章中的示例:

    public class NutritionFacts {
        // Parameters initialized to default values (if any)
        private int servingSize  = -1; // Required; no default value
        private int servings     = -1;  //     "     "      "      "
        private int calories     = 0;
        private int fat          = 0;
        private int sodium       = 0;
        private int carbohydrate = 0;
    
        public NutritionFacts() { }
        // Setters
        public void setServingSize(int val)  { servingSize = val; }
        public void setServings(int val)     { servings = val; }
        public void setCalories(int val)     { calories = val; }
        public void setFat(int val)          { fat = val; }
        public void setSodium(int val)       { sodium = val; }
        public void setCarbohydrate(int val) { carbohydrate = val; }
    }
    
    public class NutritionFacts {
        private final int servingSize;  // (mL)            required
        private final int servings;     // (per container) required
        private final int calories;     //                 optional
        private final int fat;          // (g)             optional
        private final int sodium;       // (mg)            optional
        private final int carbohydrate; // (g)             optional
    
        public NutritionFacts(int servingSize, int servings) {
            this(servingSize, servings, 0);
        }
    
        public NutritionFacts(int servingSize, int servings,
                int calories) {
            this(servingSize, servings, calories, 0);
        }
    
        public NutritionFacts(int servingSize, int servings,
                int calories, int fat) {
            this(servingSize, servings, calories, fat, 0);
        }
    
        public NutritionFacts(int servingSize, int servings,
                int calories, int fat, int sodium) {
            this(servingSize, servings, calories, fat, sodium, 0);
        }
    
        public NutritionFacts(int servingSize, int servings,
               int calories, int fat, int sodium, int carbohydrate) {
            this.servingSize  = servingSize;
            this.servings     = servings;
            this.calories     = calories;
            this.fat          = fat;
            this.sodium       = sodium;
            this.carbohydrate = carbohydrate;
        }
    }
    
    public class NutritionFacts {
        private final int servingSize;
        private final int servings;
        private final int calories;
        private final int fat;
        private final int sodium;
        private final int carbohydrate;
    
        public static class Builder {
            // Required parameters
            private final int servingSize;
            private final int servings;
    
            // Optional parameters - initialized to default values
            private int calories      = 0;
            private int fat           = 0;
            private int carbohydrate  = 0;
            private int sodium        = 0;
    
            public Builder(int servingSize, int servings) {
                this.servingSize = servingSize;
                this.servings    = servings;
            }
    
            public Builder calories(int val)
                { calories = val;      return this; }
            public Builder fat(int val)
                { fat = val;           return this; }
            public Builder carbohydrate(int val)
                { carbohydrate = val;  return this; }
            public Builder sodium(int val)
                { sodium = val;        return this; }
    
            public NutritionFacts build() {
                return new NutritionFacts(this);
            }
        }
    
        private NutritionFacts(Builder builder) {
            servingSize  = builder.servingSize;
            servings     = builder.servings;
            calories     = builder.calories;
            fat          = builder.fat;
            sodium       = builder.sodium;
            carbohydrate = builder.carbohydrate;
        }
    }
    
    您可以使用伸缩构造函数。它可以使对象不可变。但是,如果您获得了许多属性,那么编写和读取代码可能会很困难。更详细地说,当您只想使用一个已设置的属性创建时,不幸的是,这是构造函数的最后一个参数,您必须设置所有参数

    文章中的示例:

    public class NutritionFacts {
        // Parameters initialized to default values (if any)
        private int servingSize  = -1; // Required; no default value
        private int servings     = -1;  //     "     "      "      "
        private int calories     = 0;
        private int fat          = 0;
        private int sodium       = 0;
        private int carbohydrate = 0;
    
        public NutritionFacts() { }
        // Setters
        public void setServingSize(int val)  { servingSize = val; }
        public void setServings(int val)     { servings = val; }
        public void setCalories(int val)     { calories = val; }
        public void setFat(int val)          { fat = val; }
        public void setSodium(int val)       { sodium = val; }
        public void setCarbohydrate(int val) { carbohydrate = val; }
    }
    
    public class NutritionFacts {
        private final int servingSize;  // (mL)            required
        private final int servings;     // (per container) required
        private final int calories;     //                 optional
        private final int fat;          // (g)             optional
        private final int sodium;       // (mg)            optional
        private final int carbohydrate; // (g)             optional
    
        public NutritionFacts(int servingSize, int servings) {
            this(servingSize, servings, 0);
        }
    
        public NutritionFacts(int servingSize, int servings,
                int calories) {
            this(servingSize, servings, calories, 0);
        }
    
        public NutritionFacts(int servingSize, int servings,
                int calories, int fat) {
            this(servingSize, servings, calories, fat, 0);
        }
    
        public NutritionFacts(int servingSize, int servings,
                int calories, int fat, int sodium) {
            this(servingSize, servings, calories, fat, sodium, 0);
        }
    
        public NutritionFacts(int servingSize, int servings,
               int calories, int fat, int sodium, int carbohydrate) {
            this.servingSize  = servingSize;
            this.servings     = servings;
            this.calories     = calories;
            this.fat          = fat;
            this.sodium       = sodium;
            this.carbohydrate = carbohydrate;
        }
    }
    
    public class NutritionFacts {
        private final int servingSize;
        private final int servings;
        private final int calories;
        private final int fat;
        private final int sodium;
        private final int carbohydrate;
    
        public static class Builder {
            // Required parameters
            private final int servingSize;
            private final int servings;
    
            // Optional parameters - initialized to default values
            private int calories      = 0;
            private int fat           = 0;
            private int carbohydrate  = 0;
            private int sodium        = 0;
    
            public Builder(int servingSize, int servings) {
                this.servingSize = servingSize;
                this.servings    = servings;
            }
    
            public Builder calories(int val)
                { calories = val;      return this; }
            public Builder fat(int val)
                { fat = val;           return this; }
            public Builder carbohydrate(int val)
                { carbohydrate = val;  return this; }
            public Builder sodium(int val)
                { sodium = val;        return this; }
    
            public NutritionFacts build() {
                return new NutritionFacts(this);
            }
        }
    
        private NutritionFacts(Builder builder) {
            servingSize  = builder.servingSize;
            servings     = builder.servings;
            calories     = builder.calories;
            fat          = builder.fat;
            sodium       = builder.sodium;
            carbohydrate = builder.carbohydrate;
        }
    }
    
    生成器允许您的代码更可读、更易于编写。它还允许您使类不可变

    文章中的示例:

    public class NutritionFacts {
        // Parameters initialized to default values (if any)
        private int servingSize  = -1; // Required; no default value
        private int servings     = -1;  //     "     "      "      "
        private int calories     = 0;
        private int fat          = 0;
        private int sodium       = 0;
        private int carbohydrate = 0;
    
        public NutritionFacts() { }
        // Setters
        public void setServingSize(int val)  { servingSize = val; }
        public void setServings(int val)     { servings = val; }
        public void setCalories(int val)     { calories = val; }
        public void setFat(int val)          { fat = val; }
        public void setSodium(int val)       { sodium = val; }
        public void setCarbohydrate(int val) { carbohydrate = val; }
    }
    
    public class NutritionFacts {
        private final int servingSize;  // (mL)            required
        private final int servings;     // (per container) required
        private final int calories;     //                 optional
        private final int fat;          // (g)             optional
        private final int sodium;       // (mg)            optional
        private final int carbohydrate; // (g)             optional
    
        public NutritionFacts(int servingSize, int servings) {
            this(servingSize, servings, 0);
        }
    
        public NutritionFacts(int servingSize, int servings,
                int calories) {
            this(servingSize, servings, calories, 0);
        }
    
        public NutritionFacts(int servingSize, int servings,
                int calories, int fat) {
            this(servingSize, servings, calories, fat, 0);
        }
    
        public NutritionFacts(int servingSize, int servings,
                int calories, int fat, int sodium) {
            this(servingSize, servings, calories, fat, sodium, 0);
        }
    
        public NutritionFacts(int servingSize, int servings,
               int calories, int fat, int sodium, int carbohydrate) {
            this.servingSize  = servingSize;
            this.servings     = servings;
            this.calories     = calories;
            this.fat          = fat;
            this.sodium       = sodium;
            this.carbohydrate = carbohydrate;
        }
    }
    
    public class NutritionFacts {
        private final int servingSize;
        private final int servings;
        private final int calories;
        private final int fat;
        private final int sodium;
        private final int carbohydrate;
    
        public static class Builder {
            // Required parameters
            private final int servingSize;
            private final int servings;
    
            // Optional parameters - initialized to default values
            private int calories      = 0;
            private int fat           = 0;
            private int carbohydrate  = 0;
            private int sodium        = 0;
    
            public Builder(int servingSize, int servings) {
                this.servingSize = servingSize;
                this.servings    = servings;
            }
    
            public Builder calories(int val)
                { calories = val;      return this; }
            public Builder fat(int val)
                { fat = val;           return this; }
            public Builder carbohydrate(int val)
                { carbohydrate = val;  return this; }
            public Builder sodium(int val)
                { sodium = val;        return this; }
    
            public NutritionFacts build() {
                return new NutritionFacts(this);
            }
        }
    
        private NutritionFacts(Builder builder) {
            servingSize  = builder.servingSize;
            servings     = builder.servings;
            calories     = builder.calories;
            fat          = builder.fat;
            sodium       = builder.sodium;
            carbohydrate = builder.carbohydrate;
        }
    }
    
    在您的示例中,我不确定为只有两个属性的类创建生成器是否非常有用


    我希望这将对您有所帮助。

    在给定的示例中,使用构建器模式没有任何价值。您可以在不使用生成器的情况下创建
    User
    对象(因为有所有的setter)。在这种特殊情况下,Builder提供给您的唯一信息是

    当存在创建有效对象的各种组合时,应该使用生成器模式。由于这一点,您不必实现许多构造函数或工厂方法

    当创建需要许多参数的有效对象时,生成器也很有用

    生成器应只负责生成有效的对象。在您的情况下,如果用户需要名和姓,则生成器不允许创建未设置这些属性的用户实例。

    从小型不可变对象开始 如果所有属性都是必需的,那么应该只使用构造函数。通过这样做,您可能会创建一个漂亮的不可变的小对象

    当您有多个可选字段时,生成器非常有用 如果有多个可选字段和不同的方法来创建对象,则需要多个构造函数

    public User (int requiredParameter) { ... }
    public User (int reqiredParameter, int optionalParameter) { ... }
    public User (int reqiredParameter, int optionalParameter, String optionalParameter2) { ... }
    public User (int reqiredParameter, String optionalParameter2) { ... }
    
    它会产生混乱的代码。很难确定应该使用哪个构造函数。
    在这种情况下,您可以使用嵌套生成器以直观的方式创建对象

    当您的构造函数有许多不同的可能性,并且其中许多类型相同时,您通常使用构建器。因此,构建器使一切都更具可读性和可重用性。构建器避免了“伸缩构造函数”反模式,在这种反模式中,所有可能的可选构造函数参数都会组合爆炸。有效Java第二版第2项中有详细讨论。这个链接提供了您应该知道的关于构建器模式使用的所有信息。我认为构建器对于构建不可变对象最有用,否则您必须将所有参数传递给构造函数。生成器模式使构造更具可读性和灵活性。但是在你的例子中,
    用户
    是可变的,所以你对构建器所能做的事情没有设置器所不能做的。Josh bloch解释了这个用例-请在你的答案中添加至少最重要的几点。完成了,我希望一切正常。