这些构建器模式之间有什么区别(如果有的话)?

use*_*847 2 java design-patterns builder

在构建器中声明父类的实例和Field使用该变量初始化每个实例并在构建器中再次单独声明每个变量然后将构建器声明为构造函数的一部分来初始化每个变量之间是否存在差异Field

public class Foo {

    public int i;
    public String s;

    private Foo(Builder builder) {
        i = builder.i;
        s = builder.s;
    }

    public static class Builder {

        private int i;
        private String s;

        public Builder i(int i) {
            this.i = i;
            return this;
        }

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

        public Foo build() {
            return new Foo(this);
        }
    }

}
Run Code Online (Sandbox Code Playgroud)
public class Foo {

    public int i;
    public String s;

    public static class Builder {

        private final Foo mFoo = new Foo();

        public Builder i(int i) {
            mFoo.i = i;
            return this;
        }

        public Builder s(String s) {
            mFoo.s = s;
            return this;
        }

        public Foo build() {
            return mFoo;
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

Bee*_*ope 5

第一种方法是规范的方法.

我认为,第二种方法的主要局限是:

  • 您不能成为Foo(您正在构建的对象)的成员,final因为它们是在构造之后分配的.
  • 您必须在构建它的类中声明构建器,以便它可以访问私有成员或setter,或者声明非私有成员或setter方法,以便Builder可以访问它们,即使该访问级别可能建设后不合适.
  • Foo正在构建的对象经历了几个可能无效的不同状态.根据您以此增量方式构造对象的方法,您可能会受限于您可以执行的验证.通常的构建器模式收集要构建的对象的所有状态,然后构建它,允许构造函数对最终状态进行所有必要的验证.
  • 构建器无法构建多个对象.在通常的构建器模式中,您可以build()多次调用以构建多个对象,可能与对构建器方法的调用交错以修改后续对象.

我可以看到第二种方法的唯一真正优点是你保存了一些样板 - 你不必在构建器对象中重新声明成员,并且可能更好的性能,因为不必将值复制出来生成器到最终对象.