【发布时间】:2010-12-10 22:58:10
【问题描述】:
动机
最近我在寻找一种方法来初始化一个复杂的对象,而无需将大量参数传递给构造函数。我尝试使用构建器模式,但我不喜欢这样一个事实,即我无法在编译时检查是否真的设置了所有需要的值。
传统的建造者模式
当我使用构建器模式创建 Complex 对象时,创建过程更加“类型安全”,因为更容易查看参数的用途:
new ComplexBuilder()
.setFirst( "first" )
.setSecond( "second" )
.setThird( "third" )
...
.build();
但现在我有一个问题,我很容易错过一个重要的参数。我可以在 build() 方法中检查它,但这只是在运行时。在编译时,如果我遗漏了什么,没有任何东西可以警告我。
增强的构建器模式
现在我的想法是创建一个构建器,如果我错过了所需的参数,它会“提醒”我。我的第一次尝试是这样的:
public class Complex {
private String m_first;
private String m_second;
private String m_third;
private Complex() {}
public static class ComplexBuilder {
private Complex m_complex;
public ComplexBuilder() {
m_complex = new Complex();
}
public Builder2 setFirst( String first ) {
m_complex.m_first = first;
return new Builder2();
}
public class Builder2 {
private Builder2() {}
Builder3 setSecond( String second ) {
m_complex.m_second = second;
return new Builder3();
}
}
public class Builder3 {
private Builder3() {}
Builder4 setThird( String third ) {
m_complex.m_third = third;
return new Builder4();
}
}
public class Builder4 {
private Builder4() {}
Complex build() {
return m_complex;
}
}
}
}
如您所见,构建器类的每个设置器都返回不同的内部构建器类。每个内部构建器类只提供一个 setter 方法,最后一个只提供一个 build() 方法。
现在对象的构造又是这样的:
new ComplexBuilder()
.setFirst( "first" )
.setSecond( "second" )
.setThird( "third" )
.build();
...但是没有办法忘记所需的参数。编译器不会接受它。
可选参数
如果我有可选参数,我会使用最后一个内部构建器类 Builder4 来设置它们,就像“传统”构建器一样,返回自身。
问题
- 这是众所周知的模式吗?它有什么特别的名字吗?
- 您发现任何陷阱吗?
- 您是否有任何想法来改进实施 - 就减少代码行而言?
【问题讨论】:
-
您的“传统构建器模式”看起来更像我所知道的 [流利界面][1]。当我听到“建造者模式”时,我想到了[设计模式“建造者”][2]。将流畅的界面称为构建器模式是否很常见,还是我在这里遗漏了什么? [1]:en.wikipedia.org/wiki/Fluent_interface [2]:en.wikipedia.org/wiki/Builder_pattern
-
@Ewan Joshua 博客将此模式称为“构建器”(但不能替代 GoF 构建器)。见rwhansen.blogspot.com/2007/07/…。所以,不知道用同名好不好,不知道是不是通用,但是作为Effective Java的读者,不觉得累赘。
-
听起来您正在尝试使用构造函数进行编译时间检查。它的同一个 Java 不支持命名参数,如 groovy 等,无需额外的构建器类即可解决此问题。
-
使用泛型实际上可以做得更好:michid.wordpress.com/2008/08/13/…
-
这是一个聪明的想法,但是您失去了使用传统构建器模式获得的很多灵活性。不仅在您指定属性的顺序方面,还包括在变量中引用正在进行的构建器和异步设置构建器属性之类的事情。您不能对您的模式执行此操作,因为每次设置属性时构建器的类型都会更改。实际上,您所做的只是创建了一个更详细的构造函数,您不必查找每个参数的含义,而必须查找方法的正确顺序。您的 IDE 可以为您提供任一方面的帮助。
标签: java design-patterns builder-pattern