Consider a class like the following
public class MyClass {
private Integer myField;
private Result result;
// more global variables
public
When we think about validation, it is generally a Composite pattern. It broadly is depicted as:
If THIS is valid, then do SOMETHING.
And as you are imposing, you want to chain up multiple checkers in a chain to perform validation in their area, you can implement a Chain of Responsibility pattern.
Consider this:
You can have a Result
Object, that can contain a message about failure as well as simple true/false.
You can have a Validator
Object, that does whatever validation is required and returns an instance of Result
.
public interface Result {
public boolean isOk();
public String getMessage();
}
// We make it genric so that we can use it to validate
// any type of Object that we want.
public interface Validator {
public Result validate(T value);
}
Now when you say that you want to validate 'X' using multiple checkers, you're imposing a Validation Rule that is nothing but a collection of Validator
objects while being an instance of Validator
itself. That being said, you can no more use the Result
object to check the validation result of your rule. You will need a composite Result
object that can keep the results as {Validator=Result}
. Doesn't it look like an implementation of HashMap
? Yes, because it is.
Now you can implement your Rule
and CompositeResult
as:
public class Rule extends ArrayList implements Validator {
public Rule(Validator> ... chain) {
addAll(Arrays.asList(chain));
}
public Object validate(Object target) {
CompositeResult result = new CompositeResult(size());
for (Validator rule : this) {
Result tempResult = rule.validate(value);
if (!tempResult.isOk())
result.put(rule, tempResult);
}
return result;
}
}
public class CompositeResult extends HashMap implements
Result {
private Integer appliedCount;
public CompositeResult(Integer appliedCount) {
this.appliedCount = appliedCount;
}
@Override
public boolean isOk() {
boolean isOk = true;
for (Result r : values()) {
isOk = r.isOk();
if (!isOk)
break;
}
return isOk;
}
@Override
public String getMessage() {
return toString();
}
public Integer failCount() {
return size();
}
public Integer passCount() {
return appliedCount - size();
}
}
And that's it! Now, to implement your checkers:
public class Checker1 implements Validator {
/* Implementation */
}
public class CheckerN implements Validator {
/* Implementation */
}
And it's time to do the validation:
Validator checkingRule = new Rule(new Checker1(), new CheckerN());
CompositeResult result = checkingRule.validate(yourParameter);
if (result.isOk())
System.out.println("All validations passed");
else
System.out.println(result.getFailedCount() + " validations failed");
Easy and neat.
I have uploaded an example in my public repo for you to play around.