Java实现构建器模式的最佳方法

时间:2014-04-19 11:33:39

标签: java builder

以下哪项是实施构建器模式的更好方法?

1)使用构建对象而不是构建器中的所有属性(并在构建器构造函数中创建它):

public class Person {
    private String firstName;
    // other properties ...

    private Person() {}

    // getters ...

    public static class Builder {
        // person object instead of all the person properties
        private Person person;

        public Builder() {
            person = new Person();
        }

        public Builder setFirstName(String firstName) {
            person.firstName = firstName;

            return this;
        }

        // other setters ...

        public Person build() {
            if (null == person.firstName) {
                throw new IllegalStateException("Invalid data.");
            }

            return person;
        }
    }
}

2)直接在构建器中使用对象的属性来构建而不是对象(并在build()方法中创建它):

public class Person {
    private String firstName;
    // other properties ...

    private Person() {}

    // getters ...

    public static class Builder {
        // person properties instead of object
        private String firstName;
        // other properties ...

        public Builder() {}

        public Builder setFirstName(String firstName) {
            this.firstName = firstName;

            return this;
        }

        // other setters ...

        public Person build() {
            if (null == this.firstName) {
                throw new IllegalStateException("Invalid data.");
            }

            Person person = new Person();
            person.firstName = firstName;

            return person;
        }
    }
}

我更喜欢第一种方式,因为我认为在构建器中有很多属性重复它们是多余的。第一种方法有一些缺点吗?

提前致谢,抱歉我的英语不好。

3 个答案:

答案 0 :(得分:9)

小注:是的,属性可能是重复的,但它们有优势

详情如下: 如果你看一下细节here

Pizza pizza = new Pizza(12);
pizza.setCheese(true);
pizza.setPepperoni(true);
pizza.setBacon(true);

这里的问题是,因为对象是在几次调用中创建的,所以在构造过程中它可能处于不一致状态。这还需要花费很多额外的精力来确保线程安全。

更好的选择是使用Builder Pattern。

请注意以下Builder中的方法以及相应的构造函数或父Pizza类 - 链接here中的完整代码

 public static class Builder {

    public Pizza build() {    // Notice this method
      return new Pizza(this);
    }
  }

  private Pizza(Builder builder) {  // Notice this Constructor
    size = builder.size;
    cheese = builder.cheese;
    pepperoni = builder.pepperoni;
    bacon = builder.bacon;
  }

答案 1 :(得分:2)

{4}“设计模式”一书中描述了Builder模式:

  

构建器模式是一种设计模式,允许使用正确的操作序列逐步创建复杂对象。构造由一个导向器对象控制,该对象只需要知道它要创建的对象的类型。

如果在构造对象时需要遵循一系列步骤,那么请选择第二个选项。

在您的第一个选项中,不会控制正确的操作序列。如果未定义操作序列,您可以选择其中一个选项。

答案 2 :(得分:1)

我认为在你的情况下无论在哪里创建对象。在两种情况下,构建器将以相同的方式使用,性能差异最小。

但是如果对象是不可变的并且它的字段可以用多个步骤创建,那么我肯定会采用第二种方法。例如,您可以检查java.lang.StringBuilder的源代码,并看到在最后一步中创建了String对象:

public String toString() {
    // Create a copy, don't share the array
    return new String(value, 0, count);
}

此外,我更喜欢向导模式。它是Builder模式的扩展,可以防止您获得IllegalStateException。

public class Person {

    private String firstName;
    // other properties ...

    private Person() {}

    // getters ...

    public static class Builder {

        public Builder() {}

        public FirstStep setFirstName(String firstName) {
            return new FirstStep(firstName);
        }

        public static class FirstStep {

            private String firstName;

            private FirstStep(String firstName) {
                this.firstName = firstName;
            }

            public Person build() {
                Person person = new Person();
                person.firstName = firstName;
                return person;
            }
        }
    }
}