tan*_*ens 39 java design-patterns builder-pattern
最近我搜索了一种初始化复杂对象的方法,而没有将大量参数传递给构造函数.我尝试使用构建器模式,但我不喜欢这样的事实,即如果我确实设置了所有需要的值,我无法在编译时检查.
当我使用构建器模式创建我的Complex
对象时,创建更"类型安全",因为它更容易看到用于什么参数:
new ComplexBuilder()
.setFirst( "first" )
.setSecond( "second" )
.setThird( "third" )
...
.build();
Run Code Online (Sandbox Code Playgroud)
但现在我遇到了问题,我很容易错过一个重要的参数.我可以在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;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,构建器类的每个setter返回不同的内部构建器类.每个内部构建器类只提供一个setter方法,最后一个只提供build()方法.
现在,对象的构造再次如下所示:
new ComplexBuilder()
.setFirst( "first" )
.setSecond( "second" )
.setThird( "third" )
.build();
Run Code Online (Sandbox Code Playgroud)
...但是没有办法忘记所需的参数.编译器不会接受它.
如果我有可选参数,我会使用最后一个内部构建器类Builder4
来设置它们像"传统"构建器那样,返回自己.
Mic*_*rdt 23
传统的构建器模式已经处理了这个问题:只需在构造函数中获取必需参数即可.当然,没有什么能阻止调用者传递null,但是你的方法也没有.
我用你的方法看到的一个大问题是你要么有一个强制参数数量的类的组合爆炸,要么强迫用户在一个特定的sqeuence中设置参数,这很烦人.
此外,还有很多额外的工作.
cli*_*nux 13
public class Complex {
private final String first;
private final String second;
private final String third;
public static class False {}
public static class True {}
public static class Builder<Has1,Has2,Has3> {
private String first;
private String second;
private String third;
private Builder() {}
public static Builder<False,False,False> create() {
return new Builder<>();
}
public Builder<True,Has2,Has3> setFirst(String first) {
this.first = first;
return (Builder<True,Has2,Has3>)this;
}
public Builder<Has1,True,Has3> setSecond(String second) {
this.second = second;
return (Builder<Has1,True,Has3>)this;
}
public Builder<Has1,Has2,True> setThird(String third) {
this.third = third;
return (Builder<Has1,Has2,True>)this;
}
}
public Complex(Builder<True,True,True> builder) {
first = builder.first;
second = builder.second;
third = builder.third;
}
public static void test() {
// Compile Error!
Complex c1 = new Complex(Complex.Builder.create().setFirst("1").setSecond("2"));
// Compile Error!
Complex c2 = new Complex(Complex.Builder.create().setFirst("1").setThird("3"));
// Works!, all params supplied.
Complex c3 = new Complex(Complex.Builder.create().setFirst("1").setSecond("2").setThird("3"));
}
}
Run Code Online (Sandbox Code Playgroud)
Mar*_*tin 12
为什么不在构建器构造函数中放入"required"参数?
public class Complex
{
....
public static class ComplexBuilder
{
// Required parameters
private final int required;
// Optional parameters
private int optional = 0;
public ComplexBuilder( int required )
{
this.required = required;
}
public Builder setOptional(int optional)
{
this.optional = optional;
}
}
...
}
Run Code Online (Sandbox Code Playgroud)
Effective Java中概述了此模式.
恕我直言,这似乎臃肿.如果必须包含所有参数,请在构造函数中传递它们.
我见过/用过这个:
new ComplexBuilder(requiredvarA, requiedVarB).optional(foo).optional(bar).build();
Run Code Online (Sandbox Code Playgroud)
然后将这些传递给需要它们的对象.
归档时间: |
|
查看次数: |
11418 次 |
最近记录: |