vendredi 25 décembre 2015

Improve builder pattern on validation check?

I recently started using Builder pattern in one of my projects and I am trying to add some sort of validations on my Builder class. I am assuming we cannot do this at compile time so that's why I am doing this validation at runtime. But may be I am wrong and that's what I am trying to see whether I can do this at compile time.

public final class RequestKey {

    private final Long userid;
    private final String deviceid;
    private final String flowid;
    private final int clientid;
    private final long timeout;
    private final boolean abcFlag;
    private final boolean defFlag;
    private final Map<String, String> baseMap;

    private RequestKey(Builder builder) {
        this.userid = builder.userid;
        this.deviceid = builder.deviceid;
        this.flowid = builder.flowid;
        this.clientid = builder.clientid;
        this.abcFlag = builder.abcFlag;
        this.defFlag = builder.defFlag;
        this.baseMap = builder.baseMap.build();
        this.timeout = builder.timeout;
    }

    public static class Builder {
        protected final int clientid;
        protected Long userid = null;
        protected String deviceid = null;
        protected String flowid = null;
        protected long timeout = 200L;
        protected boolean abcFlag = false;
        protected boolean defFlag = true;
        protected ImmutableMap.Builder<String, String> baseMap = ImmutableMap.builder();

        public Builder(int clientid) {
            checkArgument(clientid > 0, "clientid must not be negative or zero");
            this.clientid = clientid;
        }

        public Builder setUserId(long userid) {
            checkArgument(userid > 0, "userid must not be negative or zero");
            this.userid = Long.valueOf(userid);
            return this;
        }

        public Builder setDeviceId(String deviceid) {
            checkNotNull(deviceid, "deviceid cannot be null");
            checkArgument(deviceid.length() > 0, "deviceid can't be an empty string");
            this.deviceid = deviceid;
            return this;
        }

        public Builder setFlowId(String flowid) {
            checkNotNull(flowid, "flowid cannot be null");
            checkArgument(flowid.length() > 0, "flowid can't be an empty string");
            this.flowid = flowid;
            return this;
        }

        public Builder baseMap(Map<String, String> baseMap) {
            checkNotNull(baseMap, "baseMap cannot be null");
            this.baseMap.putAll(baseMap);
            return this;
        }

        public Builder abcFlag(boolean abcFlag) {
            this.abcFlag = abcFlag;
            return this;
        }

        public Builder defFlag(boolean defFlag) {
            this.defFlag = defFlag;
            return this;
        }

        public Builder addTimeout(long timeout) {
            checkArgument(timeout > 0, "timeout must not be negative or zero");
            this.timeout = timeout;
            return this;
        }

        public RequestKey build() {
            if (!this.isValid()) {
                throw new IllegalStateException("You have to pass at least one"
                        + " of the following: userid, flowid or deviceid");
            }
            return new RequestKey(this);
        }

        private boolean isValid() {
            return !(TestUtils.isEmpty(userid) && TestUtils.isEmpty(flowid) && TestUtils.isEmpty(deviceid));
        }
    }

    // getters here
}

Problem Statement:

In my above builder pattern, I have only one parameter mandatory clientId and rest of them are optional but I need to have either userid, flowid or deviceid set. If none of those three are set then I am throwing IllegalStateException with an error message as shown above in the code. That check I am doing at runtime. I want to do this check at compile time if possible by any chance and don't build my pattern unless everything is provided?

It is not mandatory that they will pass all those three id's everytime, they can pass all three or sometimes two or sometimes only one but the condition is either one of them should be set.

How can I improve my builder pattern so that I can do id validation at compile time only instead of doing this at runtime?

I found out this SO link which exactly talks about same thing but not sure how can I use it in my scenario? And also this builder pattern with a twist and this SO question

Can anyone provide an example how can I fix this in my builder pattern?

Aucun commentaire:

Enregistrer un commentaire