Reputation: 170
I am in the design phase of a project which needs to perform certain validations on a given object. The validations can be grouped into 5 distinct groups. Each individual category of validator can have multiple versions differing slightly in their implementations.
public interface Validator {
boolean validate(Object o);
}
public abstract CostValidator implements Validator {
//common logic related to cost validator
}
public class CostValidator1 extends CostValidator {
boolean validate(Object o) {
//implementation 1
}
public class CostValidator2 extends CostValidator {
boolean validator(Object o) {
//implementation 2
}
Based on the business group of the object, either CostValidator1 or CostValidator2 needs to be executed.
For each business group, I plan on maintaining a list of such validators in a configuration system i.e:
BusinessGroupA {
validators = [CostValidator1, SomeOtherValidator2...]
}
BusinessGroupB {
validators = [CostValidator2, AnotherValidator99...]
}
The processing flow will fetch the list of validators from the configuration based on the business group and execute the validations in each of the validators thus contained.
Are there any flaws with this approach? Or is there any better way to address the use-case I described?
Upvotes: 3
Views: 292
Reputation: 527
I would propose to add two improvements to the above solution:
1. Guarantee the presence of required validation rules
Assuming that for each business group relevant validations should be executed, there should be some mechanism to guarantee that the configuration specifies enough validation rules, i.e. validation classes. If you have tens of properties and maybe hundreds of business groups, it would be too easy to make an error in the configuration, i.e. not specify any validator for Cost. My suggestion would be to specify on the level of business object which properties need to have a validator. Then create some kind of object factory that will bind validators to the object based on business group and validation requirement.
I would follow this approach:
In your configuration keep a list of validator interfaces that are required for the business object, e.g.:
requiredValidators = [ICostValidator, IWeightValidator];
When executing the validation on BusinessGroupA or BusinessGroupB, always check if the configured validators implement all of the requiredInterfaces.
2. Decouple the validators from the specific business object
If you look at cost and weight validation now they are bound to the business object. I do not know the rest of your class diagram, but I could imagine that the properties for cost and weight would appear in multiple business objects, like for example Item, QuotationLine, SalesOrderLine, ShippingLine etc. Then it would be good to have validators that do not directly depend on the business object and can be easily applied to multiple business objects. In the object factory you could also take care of the proper binding between validators and underlying objects.
Let me know if you would like some code examples.
Upvotes: 1