-3

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

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

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 对象,这个内部类中的 build 方法返回一个新的 Person 对象?

5) 看来要创建这个 Person 类,我必须将内存使用量增加一倍,一个用于外部类,一个用于内部类,这样效率低吗?

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

7)有人将如何对此进行单元测试?如何对 setter 和 getter 进行单元测试?

8) 我可以对任何字段进行验证吗?

9)我如何指定一个字段是必需的,所以如果有人试图构建一个只有名字但没有提供姓氏的字段,它将引发异常。

提前谢谢了!

4

1 回答 1

3
  1. 我不明白这个。类中没有定义构造函数Builder,这意味着编译器会自动生成一个无参数的构造函数。

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

  3. 这是一个工厂方法的例子。目前,它只是创建一个实例Builder并返回它,但在未来,这可能会更改为,例如,创建一个实例并在返回之前对其进行修改,或者在返回实例之前执行安全检查。

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

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

  6. 是的,你可以,因为类中有一个public构造函数,Person它接受两个String对象。

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

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

  9. (我假设您的意思是,如果传入null值,由于默认初始化就会出现这种情况。)您可以利用java.util.ObjectsJava 7 中引入的类中引入的一种方便的方法,Objects.requireNonNull(). 传递一个参数给它,如果参数是null. 否则,它将返回参数。

于 2013-08-24T06:00:52.580 回答