我最近学习了Joshua Bloch 的构建器模式,用于创建具有许多可选字段的对象。多年来我一直在使用类似的东西,但在 Bloch 的书向我推荐之前从未使用过内部类。我喜欢它。
我知道另一个线程可能会在实际构建之前(使用build()
)更改 bulider 的配置,因此可能需要重新验证封闭类的构造函数中的所有值。下面是一个可选地重新验证其数据的构建器类的示例。
所以我的问题是:假设这是一个足够健壮的设计,当所有值都有默认值时——知道这个类是使用默认值的糟糕选择——并且当每个设置尝试都得到验证时,是否需要重新检查? 虽然它可能不同,但它永远不会无效。那是对的吗?
(尽管这种设计是易于管理的,但由于可能需要重新验证,它肯定会变得复杂。而且,老实说,我从不使用多线程,但我不想让我的库无法被这样做的人使用。)
谢谢你的任何建议。
/**
<P><CODE>java ReverifyBuilderInEnclosingCnstrXmpl</CODE></P>
**/
public class ReverifyBuilderInEnclosingCnstrXmpl {
public static final void main(String[] igno_red) {
//Don't reverify
ReverifyBuilderInEnclosingCnstrXmpl rvbdx = new ReverifyBuilderInEnclosingCnstrXmpl.Cfg().
name("Big Bird").age(6).build();
System.out.println(rvbdx.sName);
System.out.println(rvbdx.iAge);
//Do reverify
rvbdx = new ReverifyBuilderInEnclosingCnstrXmpl.Cfg().
reverifyInEnclosing().
name("Big Bird").age(6).build();
}
public final String sName;
public final int iAge;
/**
<P>Create a new <CODE>ReverifyBuilderInEnclosingCnstrXmpl</CODE> with defaults.</P>
**/
public ReverifyBuilderInEnclosingCnstrXmpl() {
//Does not reverify. No need.
this(new ReverifyBuilderInEnclosingCnstrXmpl.Cfg());
}
private ReverifyBuilderInEnclosingCnstrXmpl(ReverifyBuilderInEnclosingCnstrXmpl.Cfg rbdx_c) {
sName = rbdx_c.sName;
iAge = rbdx_c.iAge;
ReverifyBuilderInEnclosingCnstrXmpl.Cfg.zcibValues(rbdx_c, sName, iAge, "constructor");
}
public static class Cfg {
private String sName = null;
private int iAge = -1;
private boolean bReVrfy = false;
public Cfg() {
//Defaults
bReVrfy = false;
name("Broom Hilda");
age(127);
}
//Self-returning configuration...START
//No way to unset.
public Cfg reverifyInEnclosing() {
bReVrfy = true;
return this;
}
public Cfg name(String s_name) {
zcib_name(s_name, "name");
sName = s_name;
return this;
}
public Cfg age(int i_age) {
zcib_age(i_age, "age");
iAge = i_age;
return this;
}
//Self-returning configuration...END
//Validate config...START
public static final void zcibValues(ReverifyBuilderInEnclosingCnstrXmpl.Cfg rbdx_c, String s_name, int i_age, String s_clgFunc) {
try {
if(!rbdx_c.bReVrfy) {
return;
}
} catch(NullPointerException npx) {
throw new NullPointerException("zcibValues: rbdx_c");
}
zcib_name(s_name, s_clgFunc);
zcib_age(i_age, s_clgFunc);
}
public static final void zcib_name(String s_name, String s_clgFunc) {
if(s_name == null || s_name.length() == 0) {
throw new IllegalArgumentException(s_clgFunc + ": s_name (" + s_name + ") is null or empty.");
}
}
public static final void zcib_age(int i_age, String s_clgFunc) {
if(i_age < 0) {
throw new IllegalArgumentException(s_clgFunc + ": i_age (" + i_age + ") is negative.");
}
}
//Validate config...END
public ReverifyBuilderInEnclosingCnstrXmpl build() {
return (new ReverifyBuilderInEnclosingCnstrXmpl(this));
}
}
}