1

看到吉米博加德的优秀video on crafting wicked domains,我试图将相同的原则应用于我现有的项目之一,以评估我如何很好地理解了这个概念。我有以下列出的疑问和疑问。领域建模:做正确

域名后台:管理员可以查看公司列表。然后他批准一家公司。数据库应该将布尔字段更新为true并存储批准公司的用户的ID。

最初,我在我的服务层中编写了以下代码。它将请求传递给更新数据库中相应字段的存储库,然后发送邮件通知。

public void ApproveCompany(int companyId, int userId) 
{ 
    _companyRep.ApproveCompany(companyId, userId); 

    //send mail to company representatives on successful approval. 
} 

为了创建丰富的域并封装域类中的逻辑,我创建了下面的代码。

public void ApproveCompany(int companyId, int userId) 
    { 
     var user = _userRep.GetById(userId); 
     var company = _companyRep.GetById(companyId); 
     user.Approve(company); 

     _companyRep.Insert(c); 

     //send mail to company representatives on successful approval. 
    } 

public class AdminUser 
    { 
     public string Name { get; set; } 

     public void Approve(MyApprovedCompany c) 
     { 
      c.SetIsApproved(this); 
     }  
    } 

public class Company 
    { 
     public bool IsApproved { get; private set; } 
     public AdminUser ApprovedBy { get; private set; } 

     public void SetIsApproved(AdminUser user) 
     { 
      if (this.IsApproved) 
       throw new Exception("This company has already been approved by user: " + user.Name); 

      this.IsApproved = true; 
      this.ApprovedBy = user; 
     } 
    } 

查询:

  1. 是我做了什么完全正确的/部分正确?
  2. 从性能的角度来看,只是为了创建适当的类实例而将两个对象取回,将来会成为一个问题?
  3. 邮件通知是否属于服务层?
  4. 我的公司资料库将如何处理与批准公司的用户有关的财产?我的公司存储库是否应该引用用户存储库(我认为这是错误的)。

或者,我可以编写服务层如下,但我不认为这是正确的。

public void ApproveCompany(int companyId, int userId) 
{ 
    var user = _userRep.GetById(userId); 
    var company = _companyRep.GetById(companyId); 

    if(company.IsApproved) 
    { 
     throw new Exception("This company has already been approved by user: " + _userRep.GetById(company.ApprovedUserId).Name);   
    } 
    else 
    { 
     user.Approve(company); 
     _companyRep.Insert(c); 
    } 
} 
+0

虽然你的问题不适合SO,下面是一些提示:当你调出存储在db中的东西时,那不是DDD。存储库仅保存/加载持久化对象。你不“创造丰富的领域”,一个领域要么富有,要么不富有。 “管理员可以查看”是用户界面关注的问题。 “管理员可以批准”是一项业务规则。适当的建模始于识别**概念**和它们的**使用案例**。 DDD没有“正确”或“错误”的方式,只是正确理解域和DDD模式。 – MikeSW

+1

@MikeSW说的另外一件事是掌握域事件。吉米的演讲没有解决这个问题,但这是什么可以启动您的电子邮件通知。 – Marco

回答

2

这些类型的问题是几乎不可能正确地回答,但这里是我可以从我所看到的告诉你:

  1. 这有点是正确的,但我通常倾向于把行为上的AR由操作而不是执行者执行。在这种情况下双重调度不会带来任何有用的IMHO。所以我简化到company.Approve(adminUser)。您可能会说adminUser.approve(Company)更好地反映了“管理员用户批准公司”这样的使用案例,但您可以将其反过来并说“公司已获得管理员用户批准”。另外请注意,您所使用的方法非常符合CRUD,并且不能很好地反映您的无处不在的语言。

  2. ARs应尽可能小。只要你没有创建不必要的大集群聚集,我不认为这成为一个问题。我强烈建议您阅读Effective Aggregate Design by Vaughn Vernon

  3. 理想情况下,您应该依靠域事件来实现操作的副作用。有关于如何在Web上实施域事件的大量信息。但是,由于缺乏发布/订阅机制,可以在应用程序服务层完成,或者您可以在AR方法级别注入邮件服务。

  4. 问题是您在另一个AR内引用AR。AR通常应该通过身份引用其他AR。因此,Company不会保留在AdminUser上,仅限于用户的ID。通过这样做,你的问题就消失了,你减少了你的AR的大小。