Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/meteor/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在域驱动设计中,将调用放在其他对象上是否违反DDD';域对象中的报告?_C#_Design Patterns_Service_Domain Driven Design - Fatal编程技术网

C# 在域驱动设计中,将调用放在其他对象上是否违反DDD';域对象中的报告?

C# 在域驱动设计中,将调用放在其他对象上是否违反DDD';域对象中的报告?,c#,design-patterns,service,domain-driven-design,C#,Design Patterns,Service,Domain Driven Design,我目前正在一个即将结束的项目中重构一些代码,最后我将许多业务逻辑放入服务类中,而不是域对象中。此时,大多数域对象只是数据容器。我决定在服务对象中编写大部分业务逻辑,然后将所有内容重构为更好、更可重用和更可读的形状。这样,我就可以决定哪些代码应该放在域对象中,哪些代码应该拆分成它们自己的新对象,哪些代码应该留在服务类中。所以我有一些代码: public decimal CaculateBatchTotal(VendorApplicationBatch batch) { IList<

我目前正在一个即将结束的项目中重构一些代码,最后我将许多业务逻辑放入服务类中,而不是域对象中。此时,大多数域对象只是数据容器。我决定在服务对象中编写大部分业务逻辑,然后将所有内容重构为更好、更可重用和更可读的形状。这样,我就可以决定哪些代码应该放在域对象中,哪些代码应该拆分成它们自己的新对象,哪些代码应该留在服务类中。所以我有一些代码:

public decimal CaculateBatchTotal(VendorApplicationBatch batch)
{
     IList<VendorApplication> applications = AppRepo.GetByBatchId(batch.Id);

     if (applications == null || applications.Count == 0)
          throw new ArgumentException("There were no applications for this batch, that shouldn't be possible");
     decimal total = 0m;
     foreach (VendorApplication app in applications)
          total += app.Amount;
     return total;
}
public decimal CaculateBatchTotal(供应商应用程序批处理)
{
IList applications=AppRepo.GetByBatchId(batch.Id);
if(applications==null | | applications.Count==0)
抛出新ArgumentException(“此批处理没有应用程序,这不可能”);
小数总数=0米;
foreach(应用程序中的供应商应用程序应用程序)
合计+=应用金额;
返回总数;
}
这段代码似乎可以很好地添加到域对象中,因为它的唯一输入参数是域对象本身。似乎是进行重构的最佳人选。但唯一的问题是这个对象调用另一个对象的存储库。这让我想把它留在服务课上

因此,我的问题是:

  • 你会把这个密码放在哪里
  • 你能把这个函数分解吗
  • 遵循严格的领域驱动设计的人会把它放在哪里
  • 为什么?
  • 谢谢你抽出时间

    编辑说明:在这个问题上不能使用ORM,所以我不能使用延迟加载解决方案

    编辑注2:我不能改变构造函数来接受参数,因为可能的数据层是如何使用反射实例化域对象的(这不是我的想法)


    编辑注3:我不认为批处理对象应该能够合计任何应用程序列表,它似乎只能合计该特定批处理中的应用程序。否则,将函数保留在服务类中对我来说更有意义。

    为什么不传入一个IList
    作为参数,而不是VendorApplicationBatch?这方面的调用代码可能来自一个可以访问AppRepo的服务。这样一来,您的存储库访问权限将上升到它所属的位置,而您的域功能仍然可以对数据来自何处一无所知。

    我不是DDD方面的专家,但我记得伟大的杰里米·米勒(Jeremy Miller)的一篇文章为我回答了这个问题。您通常需要与域对象相关的逻辑—在这些对象内部,但您的服务类将执行包含此逻辑的方法。这帮助我将特定于域的逻辑推送到实体类中,并使我的服务类不那么庞大(正如我发现自己在服务类中加入了很多逻辑,如您所提到的)

    编辑:示例

    我使用企业库进行简单验证,因此在entity类中我将设置如下属性:

     [StringLengthValidator(1, 100)]
     public string Username {
         get { return mUsername; }
         set { mUsername = value; }
     }
    
    实体继承自基类,该基类具有以下“IsValid”方法,该方法将确保每个对象满足验证标准

         public bool IsValid()
         {
             mResults = new ValidationResults();
             Validate(mResults);
    
             return mResults.IsValid();
         }
    
         [SelfValidation()]
         public virtual void Validate(ValidationResults results)
         {
             if (!object.ReferenceEquals(this.GetType(), typeof(BusinessBase<T>))) {
                 Validator validator = ValidationFactory.CreateValidator(this.GetType());
                 results.AddAllResults(validator.Validate(this));
             }
             //before we return the bool value, if we have any validation results map them into the
             //broken rules property so the parent class can display them to the end user
             if (!results.IsValid()) {
                 mBrokenRules = new List<BrokenRule>();
                 foreach (Microsoft.Practices.EnterpriseLibrary.Validation.ValidationResult result in results) {
                     mRule = new BrokenRule();
                     mRule.Message = result.Message;
                     mRule.PropertyName = result.Key.ToString();
                     mBrokenRules.Add(mRule);
                 }
             }
         }
    
    一个更复杂的例子可能是银行账户。存款逻辑将存在于account对象中,但服务类将调用此方法。

    据我所知(没有足够的信息知道这是否是正确的设计),VendorApplicationBatch应在域对象中包含一个延迟加载的IList,并且逻辑应保留在域中

    例如(航空代码):

    公共类供应商应用程序批处理{
    私有IList应用程序{get;set;};
    公共十进制CaculateBatchTotal()
    {
    if(Applications==null | | Applications.Count==0)
    抛出新ArgumentException(“此批处理没有应用程序,这不可能”);
    小数总数=0米;
    foreach(应用程序中的供应商应用程序应用程序)
    合计+=应用金额;
    返回总数;
    }
    }
    

    使用像NHibernate这样的ORM很容易做到这一点,我认为这将是最好的解决方案。

    您甚至不应该从域对象访问存储库

    您可以做的是让服务为域对象提供适当的信息,或者在由服务或构造函数设置的域对象中有一个委托

    public DomainObject(delegate getApplicationsByBatchID)
    {
        ...
    }
    

    在我看来,CalculateTotal是一个针对VendorApplication集合的服务,返回批次的VendorApplication集合自然符合Batch类的属性。因此,其他一些服务/控制器/任何东西将从批中检索VendorApplication的适当集合,并将它们传递给VendorApplicationTotalCalculator服务(或类似的服务)。但这可能会破坏某些DDD聚合根服务规则或我不知道的类似规则(DDD新手)。

    如果我将汇总一个批的代码放在存储库中,而不是getbybatchid,则无法保证传入的应用程序将来自该批。我觉得batch应该只能合计它包含的应用程序。totals a batch in the repository->totals a batch in the batch domain object我不确定我是否理解。我的建议是保持代码的原样,但不要在应用程序列表中传递VendorApplicationBatch。GetByBatchID仍在存储库中,总计的代码仍在域中。public decimal CalculateBatchTotal(IList应用程序)我正在尝试决定是否应将此函数放入VendorBatchApplication对象中。似乎一个批处理只能处理所有应用程序
    public class VendorApplicationBatch  {
    
        private IList<VendorApplication> Applications {get; set;};   
    
        public decimal CaculateBatchTotal()
        {
            if (Applications == null || Applications.Count == 0)
                throw new ArgumentException("There were no applications for this batch, that shouldn't be possible");
    
            decimal Total = 0m;
            foreach (VendorApplication App in Applications)
                Total += App.Amount;
           return Total;
        }
    }
    
    public DomainObject(delegate getApplicationsByBatchID)
    {
        ...
    }