3 votes

Vérifier qu'un objet est correctement construit en Java

Il s'agit d'une question/problème général que j'ai rencontré. Je me demande si quelqu'un connaît des modèles ou des techniques de conception bien adaptés.

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
}

La classe ci-dessus prend des objets externes dans une file d'attente et construit des objets MyBuilderClass.

Un objet MyBuilderClass est construit avec succès si tous les champs ont reçu des valeurs non nulles et non vides.

Il y aura de nombreux objets MyBuilderClass qui ne pourront pas être construits parce que des données seront manquantes dans l'ExternalObject.

Mon problème, quelle est la meilleure façon de détecter si un objet a été correctement construit ?

  • Je pourrais vérifier la présence de valeurs nulles ou vides dans les méthodes set et lancer une exception. Le problème avec cette approche est que la levée d'exceptions est coûteuse et qu'elle va encombrer les fichiers journaux car il y aura de nombreux cas où un objet ne pourra pas être construit ;

Quelles autres approches pourrais-je utiliser ?

0voto

Sweeper Points 1267

Corrigez-moi si je me trompe : vous essayez de trouver un bon moyen de vérifier si un objet est valide, et s'il ne l'est pas, d'en informer le code client sans utiliser d'exception.

Vous pouvez essayer une méthode d'usine :

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

Vous savez maintenant si un objet est valide sans avoir recours à une exception. Il vous suffit de vérifier si la valeur retournée par initWithExternalObject est nulle.

0voto

Ralf Kleberhoff Points 3938

Je ne lancerais pas d'exceptions dans des cas qui ne sont pas exceptionnels. Et comme la seule façon pour un constructeur de ne pas produire d'objet est de lancer, vous ne devriez pas retarder la validation au constructeur.

Je recommanderais toujours que le constructeur lance l'appel si ses résultats sont invalides, mais il devrait y avoir une validation avant cela, afin que vous n'appeliez pas le constructeur avec un résultat invalide. ExternalObject .

C'est à vous de décider si vous voulez l'implémenter comme une méthode statique. boolean MyBuilderClass.validate(ExternalObject) ou en utilisant le modèle de construction avec cette validation.

0voto

Une autre approche pour une telle validation consiste à utiliser java Annotations :

  1. Créez une classe d'annotation simple, par exemple Validate :

    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @interface Validate {
    boolean required() default true;
    }
  2. puis annotez les champs que vous voulez voir apparaître en tant que @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. Et ensuite ajouter cette méthode dans le MyBuilderClass afin de vérifier si votre objet est construit correctement :

    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. Voici un exemple d'utilisation :

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

    }

Salida : true car l'objet est correctement construit.

Cela vous permettra de choisir les champs que vous voulez avoir dans la structure par réflexion, sans apporter ceux hérités d'une classe de base.

-1voto

David Fischer Points 45

D'après ce que j'ai vu, vous pourriez écraser la méthode equals de votre objet et le comparer avec un objet d'exemple valide. C'est sale et cela peut ne fonctionner que dans certains cas.

Votre approche est la meilleure à laquelle je pouvais penser. Ecrivez une méthode ou une classe séparée qui possède par exemple une méthode de validation statique. Vous pourriez la réutiliser partout.

-1voto

PillHead Points 430

Comme le suggère cette réponse précédente, voici 2 options dont l'une ou l'autre doit être ajoutée après avoir essayé de définir les variables.

utiliser la réflexion pour vérifier si l'une des variables est nulle. (Comme mentionné dans les commentaires, cela vérifiera tous les champs de cet objet mais faites attention aux champs des superclasses).

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

effectuer un contrôle de nullité sur chaque variable.

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

Réponse précédente

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X