我只是想摆脱典型的N-Tier存储库/服务/演示架构的舒适区域,并开始使用Aggregates查看DDD,我不得不承认我有点困惑,希望有人可以澄清以下示例:
如果我有一个名为News,NewsImage和Customer的实体,它们都是EF可持续存在的对象,如下所示:
public class Customer
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
public class NewsImage
{
public virtual int Id { get; set; }
public virtual byte[] Data { get; set; }
public virtual News News { get; set; }
}
public class News
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual ICollection<NewsImage> NewsImages { get; set; }
public virtual Customer Customer { get; set; }
}
据我所知,这些可能是我们用来将域对象持久保存到数据库的对象,但如果我们使用域模型中的聚合,我们就可以这样:
public class NewsAggregate
{
public int Id { get; set; }
public string Name { get; set }
public void AddImageToNews(byte[] imageData)
{
// Hide NewsImage or that object and add the byte[] data here?
}
}
我的问题随之而来,我将不胜感激,因为我确信我在这里误解了基本原则:
非常感谢任何见解,我一直在阅读并查看展示概念的示例项目,但似乎并没有完全解释实现这一目标的最佳方法。
答案 0 :(得分:2)
首先:DDD并不建议您使用任何特定的架构。我已经使用了许多不同的DDD架构,你应该使用对任务有益的东西。显然,如果你以数据驱动的方式思考,你会遇到许多DDD问题。
DDD是一种旨在应对复杂业务规则的方法。如果您的应用程序价值属于技术资产(如在云中,暴露Web服务或一些不错的html5 /移动UI),那么您不应该使用它,而是处理它处理的业务的复杂性。 您不应该将DDD用于简单的业务规则。经验法则是:如果您不需要域专家来理解业务,则根本不需要DDD。
然后,为了正确理解聚合,你应该阅读Vernon的essay on the topic。 该文章解释了聚合存在以确保业务不变量。 您永远不应该使用聚合只是来优化数据库访问。
答案 1 :(得分:2)
1)这取决于容量。有一条规则规定聚合只能直接引用其他聚合 - 而不是其他聚合中包含的实体或值对象。这是为了将聚合强制实施为一致性边界 - 它们完全封装了它们“聚合”的内容。每个聚合应该有一个存储库。表示层和任何外层可能需要以两种常规容量引用聚合 - 用于显示目的或用于行为目的。聚合不应过多关注它的显示方式,因为查询可以使用更适合任务的不同模型来实现 - read-model。相反,聚合应该关注行为。是的,在表示层希望在聚合上执行行为的情况下,它应该通过其标识引用聚合。更好的是,创建一个application service来封装域层,并将行为公开为一个简单的外观。
此外,聚合不是单个类,而是通常围绕聚合根(一个实体)聚集的一组类。您不一定需要一个单独的类来表示聚合,它可能只是根实体。
2)对于持久性,似乎您正在使用EF,它应该为您处理所有更改跟踪。它应该跟踪哪些对象是持久的或哪些是瞬态的。像NHibernate这样的ORM也可以这样做。
2.1)这取决于Customer
本身是否为聚合。如果是,则News
应仅按ID引用Customer
。此外,新闻实体可能需要客户,在这种情况下,客户ID应该传递给新闻实体的构造者。如果不需要,则存在将客户与新闻实体相关联的行为。从域的角度考虑这一点 - 将客户与新闻实体相关联的含义是什么?尽量避免以AddCustomer
这样的技术CRUD方式思考,并考虑周围的商业意图。
正如 Giacomo Tesio 所指出的,DDD在业务逻辑中具有一定复杂性的域中显示其价值。如果您的所有行为都可以映射到CRUD,那么请将其保留为CRUD。否则,请在您的域中查找行为,而不是关注数据。您的实体和值对象应该尽可能地暴露行为并隐藏状态。请阅读并重新阅读引用的文章:Effetive Aggregate Design by Vaughn Vernon。