检查对象是否正确内置 Java

Checking an object is correctly built in Java

这是我遇到的一个将军issue/problem。我想知道是否有人知道任何适合的设计模式或技术。

private ExternalObject personObject; 
private String name;
private int age;
private String address;
private String postCode;

public MyBuilderClass(ExternalObject obj)
     this.personObject=obj;
     build();
}

public build() {
    setName(personObject.getName());
    setAge(personObject.getAge());
    setAddress(personObject.getAddress());
    setPostCode(personObject.getPostCode());
    .
    .
    . many more setters
}

上面的 class 从队列中获取外部对象并构造 MyBuilderClass 对象。

如果所有字段都设置为非空非空值,则成功构建 MyBuilderClass 对象。

将有许多无法构建的 MyBuilderClass 对象,因为 ExternalObject 中将缺少数据。

我的问题是,检测对象是否已正确构建的最佳方法是什么?

我还可以使用哪些其他方法?

据我所知,您可以覆盖对象的 equals 方法并将其与有效的示例对象进行比较。它很脏,可能只在某些情况下有效。

你的方法是我能想到的最好的方法。编写一个单独的方法或 class,例如具有静态验证方法。您可以在任何地方重复使用它。

正如之前的答案所暗示的,这里有 2 个选项,其中一个应该在您尝试设置变量后添加。

使用反射检查是否有任何变量为空。 (如评论中所述,这将检查该对象中的所有字段,但要小心任何超类中的字段)。

public boolean checkNull() throws IllegalAccessException {
    for (Field f : getClass().getDeclaredFields())
        if (f.get(this) != null)
            return false;
    return true;            
}

对每个变量执行空值检查。

    boolean isValidObject = !Stream.of(name, age, ...).anyMatch(Objects::isNull);

Previous answer

如果我错了请纠正我:您正在尝试找到一种检查对象是否有效的好方法,如果不是,请在不使用异常的情况下将此告诉客户端代码。

你可以试试工厂方法:

private MyBuilderClass(ExternalObject obj)
     this.personObject=obj;
     build();
}

public static MyBuilderClass initWithExternalObject(ExternalObject obj) {
    // check obj's properties...
    if (obj.getSomeProperty() == null && ...) {
        //  invalid external object, so return null
        return null;
    } else {
        // valid
        MyBuilderClass builder = new MyBuilderClass(obj);
        return builder.build();
    }
}

现在你知道一个对象是否有效而不使用异常。你只需要检查 initWithExternalObject 返回的值是否为 null.

我不会在没有异常的情况下抛出异常。由于构造函数不生成对象的唯一方法是抛出,因此您不应延迟对构造函数的验证。

我仍然建议构造函数在其结果无效时抛出异常,但在此之前应该进行验证,因此您甚至不要使用无效 ExternalObject 调用构造函数。

是否要将其实现为静态方法boolean MyBuilderClass.validate(ExternalObject)或通过此验证使用构建器模式,由您决定。

这种验证的另一种方法是使用 java Annotations:

  1. 做一个简单的注释class,假设Validate

    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @interface Validate {
    boolean required() default true;
    }
    
  2. 然后将您要显示的字段注释为 @Validate(required=true):

    class MyBuilderClass {
    private ExternalObject externalObject;
    
    @Validate(required=true)
    private String name;
    
    @Validate(required=false) /*since it's a primitive field*/
    private int age;
    
    @Validate(required=true)
    private String address;
    
    @Validate(required=true)
    private String postCode;
    
    
    MyBuilderClass(ExternalObject externalObject) {
        this.externalObject = externalObject;
        build();
    }
    
    public void build() {
        setName(personObject.getName());
        setAge(personObject.getAge());
        setAddress(personObject.getAddress());
        setPostCode(personObject.getPostCode());
    }
    //.
    //.
    //. many more setters
    
     }
    
  3. 然后在MyBuilderClassclass中添加这个方法,为了检查你的Object是否构建正确:

    public boolean isCorrectlyBuilt() throws IllegalAccessException {
       boolean retVal = true;
      for (Field f : getClass().getDeclaredFields()) {
        f.setAccessible(true);
        boolean isToBeChecked = f.isAnnotationPresent(Validate.class);
        if (isToBeChecked) {
            Validate validate = f.getAnnotation(Validate.class);
            if (validate.required()/*==true*/) {
                if (f.get(this) == null) {
                    retVal = false;
                    break;
                    /* return false; */
                }
            }
        }
    }
    return retVal;
    }
    
  4. 下面是一个使用示例:

     public static void main(String[] args) throws Exception {
      ExternalObject personObject = new ExternalObject();
      personObject.setAge(20);
      personObject.setName("Musta");
      personObject.setAddress("Home");
      personObject.setPostCode("123445678");
    
      MyBuilderClass myBuilderClass = new MyBuilderClass(personObject);
      System.out.println(myBuilderClass.isCorrectlyBuilt());
    

    }

Output : true 因为对象构建正确。

这将允许您通过反射选择您想要在结构中的字段,而无需带来从基础 class 继承的字段。