You can do the following:
define an abstract Check class, as follows:
public abstract class Check {
private final List<Check> subChecks = new ArrayList<Check>();
public Check add(Check subCheck) { subChecks.add(subCheck); return this }
public void run(Data dataToInspect, List<Error> errors) {
Error e = check(dataToInspect);
if (e != null) {
errors.add(e);
return;
}
for (Check subCheck : subChecks) {
subCheck.run(dataToInspect, errors);
}
}
// Returns null if dataToInspect is OK.
public abstract Error check(Data dataToInspect);
}
class Data
is the class holding the data (that needs to be checked). Can be a String, a JSON object, what have you.
class Error
represents a problem detected in the data should be roughly something like:
public class Error {
private String problem;
public Error(String problem) { this.problem = problem }
public String getProblem() { return problem }
// maybe additional fields and method to better describe the detected problem...
}
You then have code that runs the check against piece of data:
public class Checker {
private final List<Error> errors = new ArrayList<Error>();
private final List<Check> checks = new ArrayList<Check>();
public Checker() {
checks.add(new DateIsParsableCheck().add(new DateIsInTheFurutreCheck());
checks.add(new UrlIsWellFormed().add(new UrlIsAccessible());
checks.add();
..
}
public void check(Data d) {
for (Check c : checks) {
Error e = c.run(d, errors);
if (e != null)
errors.add(e);
}
}
}
Slightly changed my original answer. In the current answer there is the notion of subchecks: if a check called x
has a subcheck called y
then the y
check will run only if the x
check succeeded. For instance, if the Date is not parseable there is no point to check it it is in the future.
In your case I think that all/most logical check should be sub-checks of a formal check.