据我所知,应该使用构建器模式,以防使用多个参数,这会使调用变得相当复杂,因为参数可能会交换位置或无法明确明确哪个参数的用途。
经验法则是在构建器的构造函数中要求强制参数,在方法中要求可选参数。然而,通常可能需要超过 4 个参数,这使得调用再次变得相当不清楚并且模式冗余。因此,也可以使用拆分为默认构造函数和每个参数的参数设置。
检查应该在构建方法中调用的自己的方法中进行,因此您可以使用super 调用它。编译时安全性仅在正确的数据类型上得到保证(只有异常 - null 是可能的,这必须在checkParameters()-方法中获取)。但是,您可以强制在 Builder 构造函数中将所有必需参数设置为需要它们 - 但如前所述,这可能会导致冗余模式。
import java.util.ArrayList;
import java.util.List;
public class C
{
public static class Builder<T extends C, B extends C.Builder<? extends C,? extends B>> extends AbstractBuilder<C>
{
protected String comp1;
protected String comp2;
protected int comp3;
protected int comp4;
protected int comp5;
protected List<Object> comp6 = new ArrayList<>();
protected String optional1;
protected List<Object> optional2 = new ArrayList<>();
public Builder()
{
}
public B withComp1(String comp1)
{
this.comp1 = comp1;
return (B)this;
}
public B withComp2(String comp2)
{
this.comp2 = comp2;
return (B)this;
}
public B withComp3(int comp3)
{
this.comp3 = comp3;
return (B)this;
}
public B withComp4(int comp4)
{
this.comp4 = comp4;
return (B)this;
}
public B withComp5(int comp5)
{
this.comp5 = comp5;
return (B)this;
}
public B withComp6(Object comp6)
{
this.comp6.add(comp6);
return (B)this;
}
public B withOptional1(String optional1)
{
this.optional1 = optional1;
return (B)this;
}
public B withOptional2(Object optional2)
{
this.optional2.add(optional2);
return (B)this;
}
@Override
protected void checkParameters() throws BuildException
{
if (this.comp1 == null)
throw new BuildException("Comp1 violates the rules");
if (this.comp2 == null)
throw new BuildException("Comp2 violates the rules");
if (this.comp3 == 0)
throw new BuildException("Comp3 violates the rules");
if (this.comp4 == 0)
throw new BuildException("Comp4 violates the rules");
if (this.comp5 == 0)
throw new BuildException("Comp5 violates the rules");
if (this.comp6 == null)
throw new BuildException("Comp6 violates the rules");
}
@Override
public T build() throws BuildException
{
this.checkParameters();
C c = new C(this.comp1, this.comp2,this.comp3, this.comp4, this.comp5, this.comp6);
c.setOptional1(this.optional1);
c.setOptional2(this.optional2);
return (T)c;
}
}
private final String comp1;
private final String comp2;
private final int comp3;
private final int comp4;
private final int comp5;
private final List<?> comp6;
private String optional1;
private List<?> optional2;
protected C(String comp1, String comp2, int comp3, int comp4, int comp5, List<?> comp6)
{
this.comp1 = comp1;
this.comp2 = comp2;
this.comp3 = comp3;
this.comp4 = comp4;
this.comp5 = comp5;
this.comp6 = comp6;
}
public void setOptional1(String optional1)
{
this.optional1 = optional1;
}
public void setOptional2(List<?> optional2)
{
this.optional2 = optional2;
}
// further methods omitted
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(this.comp1);
sb.append(", ");
sb.append(this.comp2);
sb.append(", ");
sb.append(this.comp3);
sb.append(", ");
sb.append(this.comp4);
sb.append(", ");
sb.append(this.comp5);
sb.append(", ");
sb.append(this.comp6);
return sb.toString();
}
}
在从 C 和构建器扩展 D 时,您需要覆盖 checkParameters() 和 build() 方法。由于使用了泛型,调用build()时将返回正确的类型@
import java.util.List;
public class D extends C
{
public static class Builder<T extends D, B extends D.Builder<? extends D, ? extends B>> extends C.Builder<D, Builder<D, B>>
{
protected String comp7;
public Builder()
{
}
public B withComp7(String comp7)
{
this.comp7 = comp7;
return (B)this;
}
@Override
public void checkParameters() throws BuildException
{
super.checkParameters();
if (comp7 == null)
throw new BuildException("Comp7 violates the rules");
}
@Override
public T build() throws BuildException
{
this.checkParameters();
D d = new D(this.comp1, this.comp2, this.comp3, this.comp4, this.comp5, this.comp6, this.comp7);
if (this.optional1 != null)
d.setOptional1(optional1);
if (this.optional2 != null)
d.setOptional2(optional2);
return (T)d;
}
}
protected String comp7;
protected D(String comp1, String comp2, int comp3, int comp4, int comp5, List<?> comp6, String comp7)
{
super(comp1, comp2, comp3, comp4, comp5, comp6);
this.comp7 = comp7;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(super.toString());
sb.append(", ");
sb.append(this.comp7);
return sb.toString();
}
}
抽象构建器类非常简单:
public abstract class AbstractBuilder<T>
{
protected abstract void checkParameters() throws BuildException;
public abstract <T> T build() throws BuildException;
}
例外也很简单:
public class BuildException extends Exception
{
public BuildException(String msg)
{
super(msg);
}
}
最后但并非最不重要的主要方法:
public static void main(String ... args)
{
try
{
C c = new C.Builder<>().withComp1("a1").withComp2("a2").withComp3(1)
.withComp4(4).withComp5(5).withComp6("lala").build();
System.out.println("c: " + c);
D d = new D.Builder<>().withComp1("d1").withComp2("d2").withComp3(3)
.withComp4(4).withComp5(5).withComp6("lala").withComp7("d7").build();
System.out.println("d: " + d);
C c2 = new C.Builder<>().withComp1("a1").withComp3(1)
.withComp4(4).withComp5(5).withComp6("lala").build();
System.out.println(c2);
}
catch (Exception e)
{
e.printStackTrace();
}
}
输出:
c: a1, a2, 1, 4, 5, [lala]
d: d1, d2, 3, 4, 5, [lala], d7
Builders.BuildException: Comp2 violates the rules
... // StackTrace omitted
不过,在对泛型进行过多处理之前,我建议坚持 KISS 政策并忘记构建器的继承,并将它们编码为简单而愚蠢的代码(其中一部分包括愚蠢的复制和粘贴)
@edit:好的,在完成所有工作并重新阅读 OP 以及链接的帖子之后,我对要求的假设完全错误 - 就像德语的措辞说:“手术成功,病人死了” -虽然我把这篇文章留在这里,以防有人想要一个类似复制和粘贴的解决方案,它实际上返回正确的类型而不是基本类型