【问题标题】:Programming pattern / architectural question编程模式/架构问题
【发布时间】:2011-01-01 15:56:55
【问题描述】:

我目前正在从事一个项目,其中我有一个 BankAccount 实体用于其他一些实体。

每个银行账户作为对银行实体、帐号和可选的 IBAN 的引用。

既然可以验证 IBAN,我如何确保为帐户设置 IBAN 时有效。什么是干净的架构方法?我目前有一个域层,没有任何其他层的引用,我喜欢这种干净的方法(我受到 Eric Evans DDD 的启发)。幸运的是,可以在不访问任何外部系统的情况下执行 IBAN 验证,所以在这种情况下,我可以有类似

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

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

感谢您的帮助!

【问题讨论】:

  • 我想你最后回答了你自己的问题。 Evans 领域驱动设计中的 SPECIFICATION 模式浮现在脑海中。

标签: architecture domain-driven-design design-patterns


【解决方案1】:

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

具体来说,我将有一个名为 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");

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

【讨论】:

  • 如果没有可用的验证器,我将对验证器进行空检查。
【解决方案2】:

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

BankAccount 实际上应该有一个可变的 IBAN 号码吗?我对银行业务不是很熟悉,但这听起来很可怕。

【讨论】:

    【解决方案3】:

    您可以为存储库实现一个使用依赖注入规范。不过,你会失去一点凝聚力。

    更多详情请见here

    【讨论】:

      【解决方案4】:

      验证逻辑的放置位置取决于执行该验证所需的信息。验证应该在有足够信息的类型中执行。另一方面,也必须考虑验证逻辑的复杂性。例如,如果您仅将电子邮件数据附加到 Person 类型,它可以在 person 类型中“就地”验证,因为验证并不复杂(假设只检查电子邮件格式)并且 Person 是唯一的消费者。另一方面,如果您拥有由 Store 和 Garage(出售您的旧东西)类型使用的交易数据(以商品数据和价格数据为特征),并且具有商品必须属于 Deal 发起者的验证逻辑,那么将验证放在 Deal 类型中是有意义的.

      【讨论】:

        【解决方案5】:

        你可以只使用一个委托来验证,你不需要传递整个接口,想要设置它的人必须有一个验证器。

        public delegate bool Validation(IBAN iban);
        void SetIBAN(IBAN iban, Validation isValid){ 
          if(!isValid(iban)) throw new ArgumentException();
        ...}
        

        【讨论】:

          【解决方案6】:

          我会使其面向方面并减少耦合。

              [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 验证属性。当然可以改进此设计,这超出了此答案的范围。

          【讨论】:

            猜你喜欢
            • 2011-07-04
            • 1970-01-01
            • 2014-11-23
            • 2019-07-02
            • 2010-09-10
            • 1970-01-01
            • 2011-06-28
            • 2021-07-04
            • 1970-01-01
            相关资源
            最近更新 更多