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

时间:2014-01-10 09:41:22

标签: java constructor builder setter builder-pattern

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

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

public final class ModelInput {

    private long userid;
    private long clientid;
    private long timeout = 500L;
    private Preference pref;
    private boolean debug;
    private Map<String, String> parameterMap;

    public ModelInput(long userid, long clientid, Preference pref, Map<String, String> 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<String, String> paramMap = new HashMap<String, String>();
paramMap.put("attribute", "segmentation");

ModelInput input = new ModelInput(109739281L, 20L, Preference.SECONDARY, paramMap, 1000L, true);

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

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

4 个答案:

答案 0 :(得分:2)

我不熟悉你所引用的那本书,但我建议你阅读post of wikipedia regarding the Builder pattern这本书很简单。

实施可能是:

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();

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

希望我帮忙!

答案 1 :(得分:2)

构建器构造函数必须具有必需参数。所以,在你的情况下,如果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<String, String> 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<String, String> parameterMap;

        public Builder(long userId, long clientId, Map<String, String> 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<String, String>();
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();

希望这会有所帮助:)

答案 2 :(得分:0)

试试这个

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,...
        }
    }
}  

答案 3 :(得分:0)

添加其他人写的内容:

为了使您的类不可变,您还需要使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实例不可变,或至少让它知道它实际上不可变。