I am in the process of writing some validation code based on these assumptions:
- Validation code must be in an external class
- i.e. no data class contains it's own validation
- The same object can be validated in different ways
- e.g. validate syntax only; validate against DB look-ups; validate against duplicates; etc
- Validation output can be different depending on what needs it
- e.g. output a single error message; output a list of all validation errors; similar but in JSON format and including error codes; etc
What combination of OO design patterns are best to solve this? A factory might be a good way to get a specific validator, but are their better approaches?
If you're doing any sort of of GUI work, you should take a look at JGoodies Validation: http://www.jgoodies.com/downloads/libraries.html (also some articles here: www.jgoodies.com/articles/).
I would create a validator for any class that needs validation. You can actually create more than one validator if you need different ways of validating, e.g. strict or not. You can group common functionality and methods into classes like AbstractValidator and ValidationResult (which may have a list of errors, severity, etc.).
Be wary of over-design. Try starting with something simple like:
or to validate a view:
It does depend on your architecture though. For example, if you automatically propagate input from the view to the domain, then you don't need to do as much validation at the view level.
One size does not fit all! Make it simple!
Provide validators with common methods/interface to output data, categorize warnings, filter/process warnings raised more than once. Do not create any sophisticated way of validation itself, at least not before writing a few real life validators.
Move out of the way and let the validators do what they are supposed to do:
I had this same problem and I found the visitor pattern to be really effective at decoupling the validation logic from the data object. You'll need to instrument your data class hierarchy with accept( visitor ) methods, but if you're building everything that's simple enough. Even if you're using a third-party hierarchy without visitor support, you can create wrappers that provide the accept traversal tree and that's pretty close to having the method inside the class.
To perform the different validation you implement a different validator class and pass it to the accept method on the root object. I was also able to create other utility visitors around the model which allowed me to create a generator visitor that filled in all the fields with sample/random data. I went a little visitor crazy on it because I was so excited. You can probably tell I'm still excited about it, especially having the change to tell someone else about it.
I think I am doing the same thing right now.
The pattern that applies here is the Filter pattern and the Filter Chain.
Each filter validates against one "way" (as you call them).
First for syntax, second for Db lookups etc (from your second bullet).