我的理解是存在构建器模式以避免多个重载的构造函数(对于比我的示例更复杂的类)
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());
}
}
}
OR
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);
}
}
}
OR
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;
}
}
}
这些是否打破了构建模式? 是否有规范正确的方法?
(我想要注意的是,甲骨文和谷歌的公约文件都没有涵盖这一点)
我知道this similar question被问到但是据我所知(尽管名称),这个问题只涵盖了实际的Builder模式和非构建模式。
我更喜欢第三种方法,但我发现的许多示例都使用了将构建器传递给构造函数的方法。我不知道我是否遗漏了一些优势/潜在问题
答案 0 :(得分:1)
我确信我的答案既不受欢迎也不会被选中,但我长期以来一直沉迷于建设者。
首先,有2个Builder模式。吹嘘的四人帮书中的一个,以及链接,经常嵌入构造函数的替换。
对于第一个,我们不必推测,本书非常清楚:构建器模式是一种创建模式,用于构造以步骤或部分完成的事物。这个想法是你有一个你处理的导演,然后导演使用许多建造者中的一个来构建产品。您正在隐藏消费者的构造细节。
在另一种情况下,经典的例子是Effective Java第2版的Bloch Static Builder。目的是:
但关于这个问题最重要的一点是,上面没有一个例子是正确的。看看这个问题的选定答案:How to use Builder pattern as described by Joshua Bloch's version in my ModelInput class?。请注意,静态构建器为每个参数都有方法,然后返回自身的实例。对链接起作用是强制性的,你不能只分配值。
我读到 Effective Java 的第3版。关于Java的最佳书籍之一。
为防止大量重载构造函数而做的这个想法并没有多大意义,除非问题仅限于使用不支持函数默认值的语言中的第二个问题参数。
答案 1 :(得分:0)
基于其他问题答案,许多博客和评论在这里 - 集体答案似乎是:
正确实现的Builder模式意味着我们可以生成完整的对象,而不必依赖多个构造函数重载并传递空值
普遍的共识是,问题中概述的第3种方法是不正确的,而第2种方法只有在生成的对象具有Xmn1023k
字段时才能被认为是正确的(不变性具有如果损坏导致编译时错误的好处,并且第一种方法是正确的,因为只需要一个构造函数(而构建器仍然允许您只提供部分数据来接收完整的对象)
如果评论被删除,我会在相关评论/反馈中添加引用:
AFAIK,正确的方法是在构造函数中放入必需的参数 - RC
正如您所知,主要思想是构建方法将返回完全构造的对象有效实例... - hovanessyan
仅传递构建器更简单,因为它避免了具有大量参数的构造函数...编译器将强制您初始化字段(如果它是最终的)...第三个不允许创建类不可变的,这通常是使用构建器的主要原因 - JB Nizet
由于构建的类是不可变的,因此它的字段都是最终的,因此向类添加字段但不是构建器会产生编译错误 - jaco0646
关于Builder是否必须是静态内部类
,this related question还有一些更有趣的答案