当前位置: 首页 > 知识库问答 >
问题:

java构建器模式用法[重复]

阴高刚
2023-03-14

最近,我看到一些开发人员使用嵌套的生成器类来编写VO,如

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为我完成代码,因为现在我也需要更新这个内部类。

    简单的POJOs携带与VO无关的代码。

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

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

    User user = new User.UserBuilder()
                    .withFirstName("Name")
                    .withLastName("surName")
                    .build();
    
  • 共有3个答案

    华子昂
    2023-03-14

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

    如果有多个可选字段和不同的方法来创建对象,则需要多个构造函数。

    public User (int requiredParameter) { ... }
    public User (int reqiredParameter, int optionalParameter) { ... }
    public User (int reqiredParameter, int optionalParameter, String optionalParameter2) { ... }
    public User (int reqiredParameter, String optionalParameter2) { ... }
    

    它创建了混乱的代码。很难确定应该使用哪个构造函数。在这种情况下,您可以使用嵌套生成器以直观的方式创建对象。

    郑旭
    2023-03-14

    恕我直言,在给定的示例中,使用生成器模式不会获得任何值。您可以在没有生成器的情况下创建 User 对象(因为所有设置器)。在这种特殊情况下,构建器为您提供的唯一内容是 Fluent 界面。

    当创建有效对象有各种组合时,应使用生成器模式。因此,您不必实现许多构造函数或工厂方法。

    当创建一个需要许多参数的有效对象时,生成器也很有帮助。

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

    韩寂离
    2023-03-14

    这是Joshua Bloch的一篇文章。他很好地解释了为什么、何时以及如何使用建筑商:http://www.informit.com/articles/article.aspx?p=1216151

    这是他的书《有效的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;
        }
    }
    

    在您的示例中,我不确定为只有两个属性的类创建生成器是否非常有用。

    希望这能帮到你。

     类似资料:
    • 我需要在没有静态嵌套类的情况下实现Builder模式。如果我有遗传,最好的方法是什么?让我们想象一下我有下面的课。 是创建一个Builder类来负责设置PassengerCar和Truck的值更好,还是我们需要另外三个类,CarBuilder,PassengerCarBuilder extends CarBuilder和TruckBuilder extends CarBuilder?

    • 本文向大家介绍设计模式构建器模式/Java 实现,包括了设计模式构建器模式/Java 实现的使用技巧和注意事项,需要的朋友参考一下 示例 通过Builder模式,您可以以易于阅读的方式创建具有许多可选变量的类的实例。 考虑以下代码: 如果所有参数都是必需的,那么一切都很好。如果有更多的变量和/或其中一些是可选的怎么办?您不想使用必需参数和可选参数的每种可能的组合来创建大量的构造函数,因为它变得难以

    • 我更喜欢第一种方式,因为我认为在构建器中重复它们是多余的。第一种方法是否存在一些缺点? 提前谢谢,抱歉我的英语不好。

    • 问题内容: 什么是一些常见的,现实世界的例子使用Builder模式的?它能买到什么?为什么不只使用工厂模式? 问题答案: 构建器和工厂恕我直言之间的主要区别在于,当你需要做很多事情来构建对象时,构建器非常有用。例如,想象一个DOM。你必须创建大量节点和属性才能获得最终对象。当工厂可以在一个方法调用中轻松创建整个对象时,将使用工厂。 使用构建器的一个示例是构建XML文档,例如在构建HTML片段时就使

    • 问题内容: 在我日常使用Java进行的工作中,我为流畅的接口使用了大量构建器,例如: 使用快捷方法Java,每个方法调用都会更改构建器实例并返回。一成不变的是,它涉及更多的类型输入,在修改之前先克隆构建器。构建方法最终会在构建器状态上进行繁重的工作。 在Scala中实现相同目标的一种好方法是什么? 如果我想,以确保被称为只有一次,随后只和可称为,一拉定向建设者,我怎么会去接近这个? 问题答案: S