与服务层接口还是直接与领域对象交互?(领域驱动设计)

5
我仍在学习DDD,有两个(可能很简单的)问题:
如果工厂创建新的对象/图形/聚合} }实例,但也从{{link4:存储库"重构"对象/图形,则:
(1)你的服务层功能/作业/任务/工作单元会调用工厂、实体实例上的行为方法或域服务函数吗?基于这些组件的责任,我迷失了对调用堆栈的理解。

(2) 实体实例是否具有像上面那样的“行为方法”?例如,一个帖子是否具有p.UpdatePost(string bodyText),或者这不是领域模型的关注点,因此应该通过存储库来实现相同的功能?或者服务层函数应在这种情况下调用存储库,而实体实例仅具有特定于领域而非持久性的行为方法?但是,为什么听起来“更新帖子”是一个领域函数,当这是用户的目标时呢?

你可以看到我很困惑,请帮忙。


我在假设一个服务层(非领域服务)应该封装接口如何与领域层交互方面是错误的吗? - Matt Kocaj
1个回答

4
(1) 你的服务层功能/任务/工作单元是否调用工厂或实体实例上的行为方法或域服务函数?我对这些组件的责任基于调用堆栈感到迷惑。
通常情况下,顶层检索必要的聚合根并调用其功能。有时顶层检索多个聚合根并将它们传递给域服务,但不经常,因为域服务是一个相当强的迹象,表明存在未识别的聚合根。最后,顶层确保聚合根被持久化。
(2) 实体实例是否具有像上面那样的“行为方法”?例如,一个帖子是否具有p.UpdatePost(string bodyText)或者这不是领域模型的关注点,因此应该通过存储库实现相同的效果?或者,服务层函数在这种情况下是否应该调用存储库,而实体实例仅具有特定于域而不是持久性的行为方法?但是,为什么听起来“更新帖子”是一个领域函数,而这是用户的目标呢?
是的,它们需要。领域模型应该意识到其状态变化,这比起初看来更有益。这个伟大的事情在于你获得了可扩展性点。如果客户一周后走向你并说他想让系统在用户更新帖子时检查其他内容,你将能够直接转到post.UpdatePost方法并在那里附加必要的东西,而不是搜索每一行post.bodyText="new value"
另一方面,CRUD与领域驱动设计并不是互相排斥的。例如,在我的应用程序中,管理用户及其角色的操作没有足够的趣味性,以至于我甚至不试图对其进行粒度建模。您需要识别业务应用程序描述和处理的重要部分。
请记住,领域驱动设计仅适用于复杂应用程序。简单的博客应用程序不需要它。
引用: (3) 我是否错误地假设服务层(而不是领域服务)应封装接口与领域层的交互方式?
据我所见- 应用服务更多是用来编排基础设施的。如果没有涉及基础设施,那么应用服务就失去了价值:

应用服务基本上只是门面。如果它增加的复杂性超过了解决的问题,那么每个门面都很糟糕。


域内:

//aggregate root is persistence ignorant. 
//it shouldn't reference repository directly
public class Customer{
  public string Name {get; private set;}
  public static Customer Register(string name){
    return new Customer(name);
  }
  protected Customer(string name){
    //here it's aware of state changes.
    //aggregate root changes it's own state
    //instead of having state changed from outside
    //through public properties
    this.Name=name;
  }
}

//domain model contains abstraction of persistence
public interface ICustomerRepository{
  void Save(Customer customer);
}

域外:

public class CustomerRepository:ICustomerRepository{
  //here we actually save state of customer into database/cloud/xml/whatever
  public void Save(Customer customer){
    //note that we do not change state of customer, we just persist it here
    _voodoo.StoreItSomehow(customer);
  }
}

//asp.net mvc controller
public class CustomerController{
  public CustomerController(ICustomerRepository repository){
    if (repository==null)throw new ArgumentNullException();
    _repository=repository;
  }
  public ActionResult Register(string name){
    var customer=Customer.Register(name);
    _repository.Save(customer);
  }
}

虽然我同意你的观点,认为博客应用程序似乎不需要采用DDD方法,但我试图通过从一个非常简化的例子开始量化我的思维变化。 - Matt Kocaj
在我的应用程序中,通常是控制器。有时是应用程序服务。它想要通过聚合根旋转业务逻辑的东西。 - Arnis Lapsa
@Arnis 太好了,这正是我想的。另一个问题:“领域模型应该知道其状态变化”——在这种情况下,您是否包括“持久性”在“状态变化”中?基于我收到的其他反馈意见,我认为您不会这样做。 - Matt Kocaj
根据我的理解,领域模型应该包含持久性的抽象,这个抽象是从外部实现和使用的。 - Arnis Lapsa
@cottsak添加了一些代码。也许这有助于解释我的意思。 - Arnis Lapsa
显示剩余2条评论

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