6

This is a follow-up of this question. I decided to implement what the accepted answer suggests, however, I realized I also needed individual public methods for each member the entity to be validated has, so it is not only validated as a whole, but also its members as separate units:

This is what was suggested:

public interface Validable {
    public void setValidator(Validator validator);
    public void validate() throws ValidationException;
    public List<String> getMessages();
}

public interface Validator<T> {
    public boolean validate(T e);
    public List<String> getValidationMessages();
}

public class EventValidator implements Validator<Event> {
    public boolean validate(Event e) {
        // validate each member here, as well as the entity as a whole
        return isValid;
    }

    // etc...
}

But now I need public methods for each member of the Event. The reason is to use each of these methods in the Event setters and methods with a similar purpose, like adding items to a list or a dictionary, initializing data, modifying data, etc.

So I would need something like:

public class EventValidator implements Validator<Event> {
    // Validates the whole object
    public boolean validate(Event e) {
        // ...
    }

    public boolean validatePlayers() {
        // ...
    }

    public boolean validateCourts() {
        // ...
    }

    public boolean validateMatches() {
        // ...
    }
}

This first thing I can see I need is to turn that Event e parameter in the "main" validate(Event e) method into a member variable so the rest of the methods can access them. But this violates the whole point of this design, which was decoupling the entity from the validator.

What would be the most fitting design to cover my needs? I wouldn't care if I had to start from scratch and totally forget about the current design.

29
  • 1
    What's stopping you from passing e to the other validateStuff() methods?
    – Ixrec
    Apr 23, 2016 at 17:57
  • 1
    Why you don't parametrize with Event all the other methods? Then all of them can be invoked from controller or from main validate method. I guess main validate method results is the sum off all others alltogether. Is'n it?
    – Laiv
    Apr 23, 2016 at 18:14
  • 1
    Ok I see why you don't stack validation calls. But interface doesn't need to have 1 method per validation. Only its implementation has them all. Anyways if you are thinking in to have a single class with all the validations possibles, the coupling is going to be hard to avoid
    – Laiv
    Apr 23, 2016 at 19:00
  • 1
    Given your choice of method names (validateCourts, validateMatches, etc.), it seems as if your individual objects should be validating themselves. What prevents you from saying something like public class Player implements Validator<Event>? Apr 23, 2016 at 19:40
  • 1
    Isn't that why you're passing an Event context? Apr 23, 2016 at 19:42

2 Answers 2

1

I think it might help to realize that Validable and Validator are interfaces that relate to the validation of a single entity, and that you are now trying to force the validation of a composite of entities into this design. Your Validator should only validate the event, do not try to use it to validate the rules for creating the event. Make a distinction between the event and the rules for creating the event.

Once you gain this insight you have many options going forward.

It seems you are modeling a tennis match. In that case, an event should probably be created by some kind of match-maker. (It might suit you to use the builder pattern?) What you are actually wanting to validate is not the event, but the steps in the process of building an event. The design you have will do a really great job at validating individual entities, but now you need to validate the rules for composing those entities into an event.

0

This is an alternative design where multiple "step" validations can be called separatelly:

==> IValidable.java <==

import java.util.List;

public interface IValidable {
    public void setValidator(IValidator<Event> validator_);
    public void validate(String stepTag) throws ValidationException, UnknownStepTagException;
    public String getLastValidationMessage();
}

==> IValidator.java <==

import java.util.List;

public interface IValidator<T> {
    public boolean validate(T e, String stepTag) throws UnknownStepTagException;
    public String getLastValidationMessage();
    public String getLastStepTag();
}

==> Event.java <==

import java.util.List;

public class Event implements IValidable {

    public static final String VALIDABLE_STEP_PLAYERS="PLAYERS";
    public static final String VALIDABLE_STEP_COURTS="COURTS";
    public static final String VALIDABLE_STEP_MATCHES="MATCHES";

    private IValidator<Event> validator;
    private String lastValidationMessage;

    @Override
    public void setValidator(IValidator<Event> validator_) {
        this.validator = validator_;
    }

    @Override
    public void validate(String stepTag) throws ValidationException, UnknownStepTagException {
        if (!this.validator.validate(this,stepTag)){
            throw new ValidationException("WTF!");
        }
    }

    @Override
    public String getLastValidationMessage() {
        return this.lastValidationMessage;
    }

}

==> SimpleEventValidator.java <==

public class SimpleEventValidator implements IValidator<Event> {

    private String lastValidationMessage ="";
    private String lastStepTag="";
    @Override
    public boolean validate(Event e, String stepTag) throws UnknownStepTagException {
        // based on the stepTag executed appropiate privateMethod
        // this example always returns false    
        this.lastStepTag=stepTag;
        return false;
    }

    @Override
    public String getLastValidationMessage() {
        return this.lastValidationMessage;
    }

    @Override
    public String getLastStepTag() {
        return this.lastStepTag;
    }

    private boolean validateThis(){
        return false;
    }

    private boolean validateThat(){
        return false;
    }       

}

==> UnknownStepTagException.java <==

public class UnknownStepTagException extends Exception {

}

==> ValidationException.java <==

public class ValidationException extends Exception {
    public ValidationException(String message) {
        super(message);
    }

    private static final long serialVersionUID = 1L;
}

==> Test.java <==

import java.util.ArrayList;
import java.util.List;

public class Test {
    public static void main (String args[]){
        Event e = new Event();
        IValidator<Event> v = new SimpleEventValidator();
        e.setValidator(v);
        List<String> messages = new ArrayList<String>();
        // set other thins to e like
        // e.setPlayers(player1,player2,player3)
        // e.setNumberOfMatches(3);
        // etc
        try {
            e.validate(Event.VALIDABLE_STEP_COURTS);
            messages.add(e.getLastValidationMessage());
            e.validate(Event.VALIDABLE_STEP_MATCHES);
            messages.add(e.getLastValidationMessage());
            e.validate(Event.VALIDABLE_STEP_PLAYERS);
            messages.add(e.getLastValidationMessage());
        } catch (ValidationException e1) {
            messages.add(e.getLastValidationMessage());
            System.out.println("Your event doesn't comply with the fedaration regulations for the following reasons: ");
            for (String s:messages){
                System.out.println(s);
            }
        } catch (UnknownStepTagException e2) {
            System.out.println("Unknown validation step "+v.getLastStepTag());
        }
    }
}

===============

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.