If I needed to input data and capture errors, I would probably do something more like:
public class Employee
{
public int EmpID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Salary { get; set; }
}
public class ErrorEmployee : Employee
{
public string[] ErrorReason { get; set; }
}
- Read CSV file row by row
- For each element i.e EmpId, FirstName... etc do the required validations by calling individual methods having validation logic. eg: public bool ValidateIsDecimal(string value) { } public bool ValidateIsEmpIdExists(string value) { } etc
- If valid, fill corresponding property of "Employees" class. Add this Class to Employees collection (eg: List)
- If NOT VALID, fill "ErrorReason" property, with appropriate reason as to what caused the validation to fail.(eg: Required filed was missing or datatype is not decimal etc) Add this Class to ErrorEmployees collection (eg: List)
I wouldn't want to pollute the regular Employee (singular, use the plural for a collection of them) object with error messages. As in the note above, check out the FluentValidation library for your validation and capture a list of errors rather than just the first found.
It is OK to delegate any logic by means of composition if that logic is going to change dynamically during the execution of a program. Complex validations like the ones you explain are as good a candidate as any to be delegated to another class via composition.
Remember though that validations can occur in different moments.
Instantiating a concrete validator like in your example is a bad idea because it couples your Event class to that particular validator.
Let's assume you are not using any DI framework.
You can add the validator to the constructor, or inject it with a setter method. I suggest a creator method in a factory instantiates both the Event and the validator and then passes it either to the event constructor or with a setValidator method.
Obviously a Validator interface and or abstract class should be writen so your classes depend on it and not on any concrete validator.
Executing the validate method in the constructor can be problematic because all the state you want to validate may not be in place yet.
I suggest that you creta a Validable interface and let your classes implement it, that interface could have a validate() method.
That way the upper components of your application call the validate method at will (which in turn is delegated to the validator member).
==> IValidable.java <==
import java.util.List;
public interface IValidable {
public void setValidator(IValidator<Event> validator_);
public void validate() throws ValidationException;
public List<String> getMessages();
}
==> IValidator.java <==
import java.util.List;
public interface IValidator<T> {
public boolean validate(T e);
public List<String> getValidationMessages();
}
==> Event.java <==
import java.util.List;
public class Event implements IValidable {
private IValidator<Event> validator;
@Override
public void setValidator(IValidator<Event> validator_) {
this.validator = validator_;
}
@Override
public void validate() throws ValidationException {
if (!this.validator.validate(this)){
throw new ValidationException("WTF!");
}
}
@Override
public List<String> getMessages() {
return this.validator.getValidationMessages();
}
}
==> SimpleEventValidator.java <==
import java.util.ArrayList;
import java.util.List;
public class SimpleEventValidator implements IValidator<Event> {
private List<String> messages = new ArrayList<String>();
@Override
public boolean validate(Event e) {
// do validations here, by accessing the public getters of e
// propulate list of messages is necessary
// this example always returns false
return false;
}
@Override
public List<String> getValidationMessages() {
return this.messages;
}
}
==> ValidationException.java <==
public class ValidationException extends Exception {
public ValidationException(String message) {
super(message);
}
private static final long serialVersionUID = 1L;
}
==> Test.java <==
public class Test {
public static void main (String args[]){
Event e = new Event();
IValidator<Event> v = new SimpleEventValidator();
e.setValidator(v);
// set other thins to e like
// e.setPlayers(player1,player2,player3)
// e.setNumberOfMatches(3);
// etc
try {
e.validate();
} catch (ValidationException e1) {
System.out.println("Your event doesn't comply with the federation regulations for the following reasons: ");
for (String s: e.getMessages()){
System.out.println(s);
}
}
}
}
Best Answer
I tend to perform all of my validation in the constructor. This is a must because I almost always create immutable objects. For your specific case I think this is acceptable.
If you are using .NET 4 you can do this. Of course this depends on whether you consider a string that contains only white space to be invalid.