How to use default value in the builder pattern if that value is not passed and also make thread safe?

AKIWEB picture AKIWEB · Jan 10, 2014 · Viewed 10.7k times · Source

I am trying to use Builder Pattern for my class..

Below is my Builder class which I have built by following Joshua Bloch version as he showed in Effective Java, 2nd Edition. Our customer will mostly pass userId, clientId always but other fields are optional and they may or may not pass it. Here Preference is an ENUM class having four fields in it.

public final class InputKeys {

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

    private InputKeys(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 {
        protected final long userId;
        protected final long clientId;
        protected long timeout;
        protected Preference preference;
        protected boolean debug;
        protected Map<String, String> parameterMap;

        public Builder(long userId, long clientId) {
            this.userId = userId;
            this.clientId = clientId;
        }

        public Builder parameterMap(Map<String, String> parameterMap) {
            this.parameterMap = parameterMap;
            return this;
        }

        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 InputKeys build() {
            return new InputKeys(this);
        }
    }
}

Below is my ENUM class -

public enum Preference {
    PRIMARY,
    SECONDARY
}    

I am making a call like this to construct the InputKeys parameter -

InputKeys keys = new InputKeys.Builder(12000L, 33L).build();    
System.out.println(keys);

The only problem here I am seeing is, if the customers are not passing any timeout value, I need to have default timeout value set as 500 always but if they are passing any timeout value then it should override my default timeout value. And this is not working for me as when I see my keys in the debug mode, it always has timeout value as 0.

Is there anything I am missing? And also I am trying to make this class immutable and thread safe.. Is this a thread safe and immutable version of Builder or I have missed something?

UPDATE:-

Specific scenarios when people will be using this is we have a factory which customers are going to use to make a call to our code. We have a simple interface which one of our class is implementing it and then we have a factory by which we will call a certain method of that implementation which accepts this keys parameter.

So they will be using the below code in there application to make a call and it might be possible they will be running there application in a multithreaded environment.

InputKeys keys = new InputKeys.Builder(12000L, 33L).build();    

IClient client = ClientFactory.getInstance();
client.getData(keys);

And then InputKeys Builder can be used multiple times to construct the keys, it's not one time. Whatever userId and clientId they will be getting they will construct the InputKeys again.

Answer

rgettman picture rgettman · Jan 10, 2014

Just initialize the timeout to 500 in the Builder. The timeout method will overwrite this value if it's called.

protected long timeout = 500L;