I am currently working on a project where I have a BankAccount entity for some other entity.
Each bank account as a reference to a bank entity, an account number and opt
Where to put validation logic depends on what information needed to perform that validation. Validation should be performed within type that has enough information to do that. On the other hand validation logic complexity must be taken into account as well. For example, if you have Email data attached only to Person type it can validated "in place" within person type because validation is not complex (assuming only email format is checked) and Person is the only consumer. If on the other hand you have deal data (characterized by goods data and price data) consumed by Store and Garage (selling your old stuff) types with validation logic that goods must belong to the Deal initiator it makes sense to put validation inside Deal type.
I would use some form of Inversion Of Control.
To be specific, I would have an interface called IIBANValidator. The various means of validating the IBAN should implement that interface. For example:
interface IBANValidator {
Boolean Validate(string iban);
}
class SqlBanValidator : IBANValidator {
public bool Validate(string iban) {
// make the sql call to validate..
throw new NotImplementedException();
}
}
Then, I would have a method in my BankAccount class which accepted an object that implements IIBANValidator and the IBAN number and was structured like (not optimized by any stretch):
Boolean SetIBAN(IIBANValidator validator, String iban) {
Boolean result = false;
if (validator.Validate(iban)) {
Iban = iban;
result = true;
}
return result;
}
At this point your BankAccount class would not have to have a dependency on your validators, you could swap them out at will, and ultimately it's very clean.
The final code would look something like:
BankAccount account = new BankAccount();
account.SetIBAN(new SqlBanValidator(), "my iban code");
Obviously at runtime you could pass any validator instance you wanted.
I'd make it aspect oriented and reduce coupling.
[IBANVlidator(Message = "your error message. can also come from culture based resouce file.")]
public string IBAN
{
get
{
return _iban;
}
set
{
this.validate();
_iban = value;
}
}
this.validate() is called from the base class of your BankAccount which iterates through all properties having validation attribute. validation atributes are custom attributes derived from ValidationAttribute class which can target class properties.
IBAN validation responsibility then is given to IBANValidator validation-attribute. of course this design can be improved which is beyond the scope of this answer.
You can just use a delegate to validate, you don't need to pass a whole interface, who ever wants to set it has to have a validator.
public delegate bool Validation(IBAN iban);
void SetIBAN(IBAN iban, Validation isValid){
if(!isValid(iban)) throw new ArgumentException();
...}
Rather than the IBAN number being a simple string, what if it was an actual class? You could implement validation in the constructor (if validation has no external dependencies), or you could use a factory to provide IBAN instances (if you need external validation). The important thing is that, if you have an IBAN instance, you know that it's a valid IBAN number.
Should BankAccount actually have a mutable IBAN number? I'm not terribly familiar with banking, but that sounds like a scary idea.
You could implement a Specification that uses Dependency Injection for the Repository. You lose a bit of cohesion, though.
More details can be found here.