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.
2 Answers 2
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.
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());
}
}
}
===============
e
to the othervalidateStuff()
methods?public class Player implements Validator<Event>
?