有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在验证检查中改进构建器模式?

我最近开始在我的一个项目中使用Builder模式,我正在尝试在我的Builder类上添加某种验证。我假设我们不能在编译时进行验证,所以我在运行时进行验证。但可能是我错了,这就是我想看看我是否能在编译时做到这一点的原因

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
}

问题陈述:

在我上面的构建器模式中,只有一个参数是必需的clientId,其余的参数是可选的,但我需要设置useridflowiddeviceid。如果这三个都没有设置,那么我将抛出带有错误消息的IllegalStateException,如代码中所示。我在运行时进行的检查。如果可能的话,我想在编译时做这个检查,除非提供了所有内容,否则不要构建我的模式

不是强制要求他们每次都要通过所有这三个id,他们可以通过所有三个,有时两个,有时只有一个,但条件是应该设置其中一个

如何改进构建器模式,以便只在编译时进行id验证,而不是在运行时进行id验证

我发现这个SOlink确切地说是关于同一件事,但不确定如何在我的场景中使用它?还有这个{a2}和这个{a3}

有人能举个例子吗?我如何在我的构建器模式中解决这个问题


共 (1) 个答案

  1. # 1 楼答案

    仅当设置了必需的属性时,才使build方法可访问:

    public class Builders {
    
      /**
       * @param args the command line arguments
       */
      public static void main(String[] args) {
    
        Builder b = new Builder(123);
    
    //    Builded instance1 = b
    //      .defFlag(false)
    //      .build(); // compile error
    
        Builder c1 = b
          .refFlag(true);
    
        Builded instance2 = b
          .setDeviceId("device id") // here's the magic, without this call `build` method would be unaccessible
          .build();
    
        Builded instance3 = b
          .refFlag(false)
          .defFlag(true)
          .setDeviceId("device id")
          .setUserId(12)
          .build();
    
        System.out.printf("%s\n%s\n", instance2, instance3);
      }
    
    }
    
    class Builded implements Cloneable {
    
      int clientId;
    
      Long userid;
      String deviceid;
      String flowid;
    
      boolean defFlag;
      boolean refFlag;
    
      public Builded(int clientId) {
        this.clientId = clientId;
      }
    
      @Override
      protected Object clone() throws CloneNotSupportedException {
        return (Builded) super.clone();
      }
    
      @Override
      public String toString() {
        return String.format("{c: %d, u: %d, d: %s, f: %s, df: %b, rf: %b}", clientId, userid, deviceid, flowid, defFlag, refFlag);
      }
    
    }
    
    class Builder {
    
      int clientId;
      protected Builded instance;
    
      private Builder() {
      }
    
      protected Builder(int clientId) {
        this.clientId = clientId;
        prepare();
      }
    
      protected final void prepare() {
        instance = new Builded(clientId);
      }
    
      private Builded build() {
        try {
          return (Builded) instance.clone();
        } catch (CloneNotSupportedException ex) {
          throw new RuntimeException(ex);
        }
      }
    
      public Builder defFlag(boolean defFlag) {
        instance.defFlag = defFlag;
        return this;
      }
    
      public Builder refFlag(boolean refFlag) {
        instance.refFlag = refFlag;
        return this;
      }
    
      public SubBuilder setUserId(long userid) {
        instance.userid = userid;
        return new SubBuilder(instance);
      }
    
      public SubBuilder setDeviceId(String deviceid) {
        instance.deviceid = deviceid;
        return new SubBuilder(instance);
      }
    
      public SubBuilder setFlowId(String flowid) {
        instance.flowid = flowid;
        return new SubBuilder(instance);
      }
    
      public static class SubBuilder extends Builder {
    
        private SubBuilder(Builded instance) {
          this.instance = instance;
        }
    
        public Builded build() {
          return super.build();
        }
    
      }
    
    }
    

    输出:

    {c: 123, u: null, d: device id, f: null, df: false, rf: true}
    {c: 123, u: 12, d: device id, f: null, df: true, rf: false}