开发者

Programming pattern / architectural question

开发者 https://www.devze.com 2022-12-15 23:50 出处:网络
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 optionally an IBAN.

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 optionally an IBAN.

Now since an IBAN can be validated, how can I ensure that when the IBAN is set for an account is valid. What would be a clean architectural approach? I currently have a domain layer without a开发者_运维百科ny reference to any other layer and I like this clean approach (I was inspired by Eric Evans DDD). Fortunately the IBAN validation can be performed without accessing any outside system so in this case I could have something like

puclic class BankAccount
{
  public string Iban
  {
     set { // validation logic here }
  }
}

But now I was thinking what approach I would use if the IBAN validation requires an SQL server check for example, or an external dll. How would I implement that. Would I create an IBAN value object which is passed to a service, that decides whether the IBAN is valid or not and after that set it to the BankAccount entity? Or would I create a factory which is allowed to instanstiate IBANs and performs validation before?

Thanks for your help!


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.


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.


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.


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();
...}


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消