编程模式/架构问题

4

我目前正在处理一个项目,其中有一个银行账户实体用于其他实体。

每个银行账户都参考了一个银行实体,一个账户号码和可选的IBAN。

现在,由于可以验证IBAN,我该如何确保当为账户设置IBAN时它是有效的。什么是清晰的架构方法?我目前有一个域层,没有任何对其他层的引用,我喜欢这种干净的方法(我受到了Eric Evans DDD的启发)。幸运的是,IBAN验证可以在不访问任何外部系统的情况下进行,因此在这种情况下,我可以像下面这样做:

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

但是现在我在思考如果IBAN验证需要例如SQL服务器检查或外部dll,我会使用什么方法。我该如何实现呢?我会创建一个IBAN值对象,将其传递给服务,该服务决定IBAN是否有效,并在此之后将其设置为BankAccount实体吗?还是我应该创建一个工厂,允许实例化IBAN并在此之前执行验证呢?

感谢您的帮助!


2
我认为你最终自己回答了这个问题。埃文斯领域驱动设计中的规范模式浮现在我的脑海中。 - David
6个回答

5

我会使用某种形式的控制反转。

具体来说,我会定义一个名为 IIBANValidator 的接口。各种验证 IBAN 的方法应该实现该接口。例如:

interface IBANValidator {
    Boolean Validate(string iban);
}

class SqlBanValidator : IBANValidator {

    public bool Validate(string iban) {
        // make the sql call to validate..
        throw new NotImplementedException();
    }

}

那么,我将在我的BankAccount类中创建一个方法,该方法接受实现了IIBANValidator接口的对象和IBAN号码,并结构化如下(没有进行任何优化):

Boolean SetIBAN(IIBANValidator validator, String iban) {
  Boolean result = false;
  if (validator.Validate(iban)) {
    Iban = iban;
    result = true;
  }

  return result;
}

在这个时候,您的BankAccount类不必依赖于您的验证器,您可以随意更换它们,最终代码非常干净。
最终代码可能如下所示:
BankAccount account = new BankAccount();
account.SetIBAN(new SqlBanValidator(), "my iban code");

显然,在运行时,您可以传递任何您想要的验证器实例。

如果验证器不可用,我会在验证器上进行空值检查。 - cjk

2

如果IBAN号码不仅仅是一个简单的字符串,而是一个实际的类,会怎样呢?你可以在构造函数中实现验证(如果验证没有外部依赖),或者你可以使用工厂来提供IBAN实例(如果你需要外部验证)。重要的是,如果你有一个IBAN实例,你知道它是一个有效的IBAN号码。

银行账户是否应该拥有可变的IBAN号码?我对银行业不太熟悉,但这听起来像个可怕的想法。


1

你可以实现一个使用依赖注入规范来操作存储库。但是这样会失去一些内聚性。

更多细节可以在这里找到。


0
你可以使用委托来进行验证,不需要传递整个接口,任何想要设置它的人都必须拥有一个验证器。
public delegate bool Validation(IBAN iban);
void SetIBAN(IBAN iban, Validation isValid){ 
  if(!isValid(iban)) throw new ArgumentException();
...}

0

我会采用面向切面编程的方式来降低耦合度。

    [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() 方法是从您的银行账户 BankAccount 的基类中调用的,它会遍历所有具有验证属性的属性。验证属性是从 ValidationAttribute 类派生的自定义属性,可以针对类属性进行目标设置。

因此,IBAN 验证的责任被分配给 IBANValidator 验证属性。 当然,这个设计可以改进,但超出了本答案的范围。


0

放置验证逻辑的位置取决于执行该验证所需的信息。验证应在具有足够信息进行验证的类型内执行。另一方面,还必须考虑验证逻辑的复杂性。例如,如果您只将电子邮件数据附加到人员类型,则可以在人员类型内“就地”验证电子邮件格式(假设仅检查电子邮件格式)并且Person是唯一的使用者,因此验证不复杂。另一方面,如果您有交易数据(由商品数据和价格数据描述),Store和Garage(销售旧物品)类型消耗,并且验证逻辑是商品必须属于交易发起者,则将验证放在Deal类型内是有意义的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接