java - 实现构建器模式的错误/正确方法是什么?

标签 java design-patterns builder anti-patterns

我的理解是,构建器模式的存在是为了避免多个重载的构造函数(对于比我的示例更复杂的类)

public class Example {

    private String a,b,c;

    public Example() {
       //setup defaults
    }

    public Example(String a) {
       this.a=a;
       //setup defaults
    }

    public Example(String a, String b) {
       this.a=a;
       this.b=b;
       //setup defaults
    }

    public Example(String a, String b, String c) {
       this.a=a;
       this.b=b;
       this.c=c;
    }

}

但是,当切换到构建器时,以下哪项是正确的方法?

public class Example {

    public static class Builder {

        //accessors

        public Example build() {
            //we setup defaults through getters
            //and example only has the 'full' constructor
            return new Example(getA(), getB(), getC()); 
        }

    }

}

或者

public class Example {

    public static class Builder {

        //accessors

        public Example build() {
            //pass in the builder and let 'Example' care about defaults
            return new Example(this); 
        }

    }

}

或者

public class Example {

    public static class Builder {

        //accessors

        public Example build() {
            //only empty constructor exists which sets all defaults
            //access fields directly to override defaults
            Example e = new Example(); 
            e.a = a;
            e.b = b;
            e.c = c;
            return e;
        }

    }

}

这些是否打破了构建器模式? 有规范正确的方法吗?

(我想指出,Oracle 和 Google 的约定文档都没有涵盖这一点)

我知道this similar question被问到,但据我所知(尽管有名称)该问题仅涵盖实际的构建器模式与非构建器模式。

我更喜欢第三种方法,但我发现的许多示例都使用将构建器传递到构造函数中的方法。我不知道我是否错过了一些优势/潜在的问题

最佳答案

我确信我的答案既不会受欢迎,也不会被选中,但我已经痴迷于构建器很长时间了。

首先,有两种构建器模式。被吹捧的《四人帮》一书中的那个,以及链接的、经常嵌入的构造函数替换。

对于第一个,我们不必猜测,书中说得很清楚:构建器模式是一种创建模式,适用于分步骤或部分完成构建的事物。这个想法是你有一个与你打交道的总监,然后总监使用多个构建器之一来构建产品。您向消费者隐瞒了施工细节。

在另一种情况下,经典示例是《Effective Java》第二版中的 Bloch Static Builder。其目的有:

  • 不变性:您可以制作具有很多属性的东西,其中大多数属性都是不可变的
  • Java 没有命名参数,复杂事物的构造在构建器中更具可读性
  • 如果您愿意,您还可以添加一些构造逻辑,例如,假设您有 5 个参数,其中一些是必需的,而一些不是,您可以将该逻辑嵌入到 build() 方法中。<

但是关于这个最需要注意的是,上面的例子都不正确。看看这个问题的选定答案:How to use Builder pattern as described by Joshua Bloch's version in my ModelInput class? 。请注意,静态构建器对每个参数都有方法,然后返回其自身的实例。这是链接正常工作所必需的,您不能只分配值。

我读到《Effective Java》即将推出第三版。即使不是关于 Java 的最好的书,也是最好的书之一。

这样做是为了防止大量重载构造函数的想法没有多大意义,除非问题仅限于在不支持函数参数默认值的语言中使用第二个构造函数。

关于java - 实现构建器模式的错误/正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47054676/

相关文章:

asp.net-mvc-3 - Asp.MVC我们可以从模型组件中调用数据库层吗?

design-patterns - 有经理设计模式这样的东西吗?

java - JPA 条件生成器 : how to replace and cast a string to numeric in order-by?

java - 编码和注释以生成 javadoc 作者姓名

javascript - 打印 JSObject 实现时出现 Nashorn 运行时异常

java - 难道真的是拒绝 parent 遗赠代码的味道吗?

java - Log4j2 RollingFileAppender 构建器方法返回类型错误

ruby - 在 Ruby 1.9 中传递 block 时生成器抛出 "wrong number of arguments"错误

java - 类不包含用于 Autowiring 的匹配构造函数

java - 不同版本的 JDK 的并发(多线程)实现有哪些变化?