如何在我的ModelInput类中使用Joshua Bloch的版本描述的Builder模式?

我正在尝试使用Builder Pattern为我的下面的类。最初我使用我的类的构造函数来设置所有参数但不小心我遇到了Builder模式,它看起来很适合我的用例。

下面是我的类,其中人们将主要传递userIdclientIdparameterMap但其他字段是可选的,它们可能会也可能不会传递它。 而且如果他们没有传递任何超时值,我需要将默认超时值设置为500,但如果他们传递任何超时值,那么它应该覆盖我的默认超时值。 这里Preference是一个有四个字段的ENUM。

 public final class ModelInput { private long userid; private long clientid; private long timeout = 500L; private Preference pref; private boolean debug; private Map parameterMap; public ModelInput(long userid, long clientid, Preference pref, Map parameterMap, long timeout, boolean debug) { this.userid = userid; this.clientid = clientid; this.pref = pref; this.parameterMap = parameterMap; this.timeout = timeout; this.debug = debug; } ... //getters here } 

下面是我最初使用如何通过将参数传递给构造函数来构造ModelInput对象的示例。 最初我传递了所有参数,但客户端主要传递userIdclientIdparameterMap ,其他字段是可选的。

 Map paramMap = new HashMap(); paramMap.put("attribute", "segmentation"); ModelInput input = new ModelInput(109739281L, 20L, Preference.SECONDARY, paramMap, 1000L, true); 

我如何将上面的代码转换为开始使用生成器模式,正如Bloch在Effective Java中所说的那样,它也是线程安全且不可变的?

如何使用Builder模式对此进行validation检查? 有可能人们可以传递userId零或负数与客户端ID和超时相同,也与map相同。

构造函数构造函数必须具有必需参数。 因此,在您的情况下,如果userId,clientId和parameterMap是必需的,我们将有类似的东西:

 public final class ModelInput { private long userid; private long clientid; private long timeout = 500L; private Preference pref; private boolean debug; private Map parameterMap; public ModelInput(Builder builder) { this.userid = builder.userId; this.clientid = builder.clientId; this.pref = builder.preference; this.parameterMap = builder.parameterMap; this.timeout = builder.timeout; this.debug = builder.debug; } public static class Builder { private long userId; private long clientId; private Preference preference; private boolean debug; private Map parameterMap; public Builder(long userId, long clientId, Map parameterMap) { this.userId = userId; this.clientId = clientId; this.parameterMap = parameterMap; } public Builder preference(Preference preference) { this.preference = preference; return this; } public Builder debug(boolean debug) { this.debug = debug; return this; } public Builder timeout(long timeout) { this.timeout = timeout; return this; } ... public ModelInput build() { return ModelInput(this); } } // ModelInput getters / setters } 

这是如何使用您的构建器类:

 String paramMap = new HashMap(); paramMap.put("attribute", "segmentation"); ModelInput.Builder builder = new ModelInput.Builder(109739281L, 20L, paramMap); builder.preference(Preference.SECONDARY).timeout(1000L).debug(true); ModelInput modelInput = builder.build(); 

希望这可以帮助 :)

我不熟悉你引用的那本书,但我建议你阅读维基百科关于Builder模式的post,这个文章很简单。

实施可以是:

 public final class ModelInput { ... public static class Builder { private long userid; ... public Builder(long userid) { this.userid = userid; } ... public ModelInput build() { return new ModelInput(this); } } private ModelInput(Builder builder){ this.userid = builder.userid; this.clientid = builder.clientid; this.pref = builder.pref; this.parameterMap = builder.parameterMap; this.timeout = builder.timeout; this.debug = builder.debug; } ... } 

然后,当您想要初始化对象时,您可以调用

 ModelInput model = new ModelInput.Builder(...).build(); 

关于validation过程,它与检查值(在构造函数中或build方法中)基本相同。

希望我帮忙!

试试这个

 public final class ModelInput { ... public static class Builder { private long userid; ... public Builder setUserId(long userId) { this.userId = userId; } ... public ModelInput build() { return new ModelInput(userId,... } } } 

添加其他人写的内容:

为了使您的类不可变,您还需要使parameterMap变量不可变。 您可以在实例化ModelInput类时执行此操作:

 private ModelInput(Builder builder){ this.userid = builder.userid; this.clientid = builder.clientid; this.pref = builder.pref; this.parameterMap = Collections.unmodifiableMap(builder.parameterMap); this.timeout = builder.timeout; this.debug = builder.debug; } 

注意使用Collections.unmodifiablemap() ;

您还需要使Preference实例不可变,或者至少让它知道它实际上不是不可变的。