构建器模式如何工作

时间:2013-08-24 05:31:48

标签: java design-patterns

Ruby(Rails)程序员已经2年了,刚换到另一个使用Java的团队。对Java builder模式有一些疑问。

我理解使用这种模式的好处,即避免伸缩构造函数和创建不一致状态的java bean setter但我无法准确理解它是如何工作的,以下是团队要求我使用的确切模式:

public class Person
{
    //why is it so important that this be final, hence immutable
    private final String firstName;
    private final String lastName;

    // Constructor
    public Person(String firstName, String lastName)
    {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    //I have absolutely no idea what is this for and why is this necessary
    public static Builder builder()
    {
        return new Builder();
    }

    //This is an inner class, where person is the outer class (the owning class)
    //but why is this has to be a static class?
    public static class Builder
    {
        private String firstName;
        private String lastName;

        public Builder withFirstName(String firstName)
        {
            //this.firstName refers to the Builder instance firstName
            this.firstName = firstName;
            return this;
            //what is this return this?  returning this instance of the Builder object?
        }

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

        public Person build()
        {
            return new Person(firstName, lastName);
            //firstName and lastName here refer to the Builder's object instance vars,
            //and used to create a new person object
        }
    }
}

使用它:

Person p = new Person.Builder(5).firstName("foo").lastName("bar").build();

1)Builder的参数“5”是什么?

2)为什么Builder内部类是静态的?

3)public static Builder builder()方法的用途是什么?

4)我是否正确我们实际上正在创建一个新的内部类 - Builder对象,该内部类中的构建方法是否返回一个新的Person对象?

5)似乎要创建这个Person类,我必须加倍内存使用,一个用于外部类,一个用于内部类,是否效率不高?

6)我是否正确我仍然可以通过Person p = new Person(“foo”,“bar”)创建一个新的人物对象;

7)有人会如何测试这个?如何对安装者和吸气剂进行单元测试?

8)我可以在任何领域进行验证吗?

9)我如何指定一个字段是必需的,所以如果有人试图构建一个只有firstName但没有提供lastName的字段,它会抛出异常。

非常感谢提前!

1 个答案:

答案 0 :(得分:1)

  1. 我不懂这个。 Builder类中没有定义构造函数,因此这意味着编译器将自动生成无参数构造函数。

  2. 如果Builder类不是静态的,则需要封闭类的实例来访问内部类。这将是一个“鸡和蛋”问题:内部类用于获取外部类的实例,但您首先需要外部类的实例来使用它! static修饰符使得它不需要外部类的实例来使用它。

  3. 这是工厂方法的示例。现在,它只是创建一个Builder的实例并返回它,但是将来可以将其更改为创建实例并在返回之前修改它,或者在返回实例之前执行安全检查

  4. 是的,你是对的。您可以创建内部类的实例,并使用其build方法获取其外部类的实例。

  5. 大多数时候,良好的设计和良好的效率之间存在权衡。但是这一次,尽管你的内存使用量增加了一倍(因为这两个类都包含两个类型为String的变量),实际的内存使用量并没有那么多。 (如果内存不足,可以通过将参数传递给JVM来更改JVM堆空间。)

  6. 是的,您可以像public类中的Person构造函数那样接收两个String个对象。

  7. 可以通过创建Builder的实例对其进行单元测试,使用其withFirstNamewithLastName方法设置名称,然后在返回的方法上调用getter方法Person对象,然后检查它们是否等于传入的值(使用String equals方法)。

  8. 您可以使用String类中的方法检查参数是否符合前提条件,如果不是则抛出异常。

  9. (我假设你的意思是如果一个人传入null的值,这是因为默认初始化的情况。)你可以利用一个方便的方法介绍在Java 7中引入的java.util.ObjectsObjects.requireNonNull()中。将参数传递给它,如果参数为null,它将抛出异常。否则,它将返回参数。