当你开始使用DDD时,这是一个常见的问题。
领域模型是一种抽象。它不应关注你使用的技术,也不代表数据库表、文档、类、函数等等。
领域模型表示概念、依赖和概念之间的相互作用。
技术用于实现领域模型。
可以使用不同的技术来实现相同的领域模型。
虽然我们想要在领域模型上拥有自由度,但实践中我们需要使用技术进行实现,有时这可能会对其产生影响。
当然,你可以放弃所有的框架和库,自己制定解决方案,使实现更加容易。即使这样做,你仍然需要考虑你的语言,例如C#、Java、Ruby等以及提供给你的工具。
以下是一个例子:
假设我们开发了一个租车系统。一个人可以租一辆车。在我们的领域中,我们有一个人所拥有的帐户的概念、汽车和汽车租赁的概念。
这就是你的领域模型。目前为止,我们不关心语言、数据库或任何东西。
现在来看领域模型的实现。
我们将使用C#。现在需要决定数据库。如果我们决定使用SQL,我们可以使用RDBMS的良好能力来进行连接,因此我们可以通过使用整数ID来实现它:
public class Account {
public int ID { get; private set; }
}
public class Car {
public int ID { get; private set; }
}
public class CarRental {
public int AccountID { get; private set; }
public int CarID { get; private set; }
}
另一方面,我们可能认为整数ID不好,因为如果你必须与其他系统和数据库移动等一起工作,可能会发生碰撞,因此我们决定思考并使用电子邮件作为帐户的唯一标识符,使用车牌号作为汽车的唯一标识符:
public class Account {
public Email Email { get; private set; }
}
public class Car {
public LicensePlace LicensePlace { get; private set; }
}
public class CarRental {
public Email AccountEmail { get; private set; }
public LicensePlace CarLicensePlace { get; private set; }
}
如果我们遵循DDD并正确将您的实体划分为聚合,则不需要在它们之间执行联接,因为它们不应在同一事务中加载或更改。
另一方面,我们可能希望在同一个数据库上构建不同的模型(也许是读模型,如果我们使用CQRS,或者我们可能需要提取报告),使用第二种方法可能会使这更加困难,因为我们失去了执行联接的能力。
另一方面,如果我们使用像MongoDB这样的NoSQL数据库,我们就无法执行联接。因此,使用整数ID不会给我们带来任何价值。
即使我们决定使用SQL数据库并且不使用整数ID,我们仍然可以使用域事件并使用它们构建其他模型和报告。
如果我们有一个分布式系统,使用联接也将无法工作,因此使用整数ID可能根本没有带来任何价值。
有时候,利用技术的能力使某些事情变得更容易,但我们让它损害了我们的系统和领域模型。
我们最终建造出的系统从技术角度来看非常强大,但它们不能做它们应该做的事情,这使它们变得无用。
一个无用的系统是无用的,无论它的实现有多好。
如果您还没有阅读过DDD 书籍,请阅读它。Eric Evans谈到了如何利用技术来帮助您或全程与您作斗争。Eric Evans还讨论了DDD如何允许自由实现,以便您不必与您的技术作斗争。
我们倾向于一直考虑持久性,这是另一件事。确实,我们大部分时间都在持久化事物,但这并不意味着领域模型是要持久化到数据库中的东西。
当我开始编程时,我从计算机图形学和建模应用程序(如3DsMax和Maya)开始。当我开始编写使用神圣的数据库的应用程序时,我真的感到很奇怪,人们不关心也不了解他们的领域,只是持久化它们并使它们工作,所有他们谈论的都是技术。
如果您热衷于计算机图形学,如果您不了解数学,则无法编写一行代码。因此,您开始学习数学。在您掌握一些知识之后,就可以编写代码了。
以游戏为例,你可能会设计一个模拟物理的物理引擎。在这个模型中,你会有像工作、功率、重力、加速度等概念。它们不需要被持久化到数据库中。例如,你会持久化你的玩家的重量,让物理引擎知道重力如何影响它,但仍然不需要将功率持久化到数据库中。这仍然是一个域模型。 功率、工作等是函数,不是聚合实体。它们仍然是你的域模型的一部分。
假设你想建立一个物理引擎。事实上,如果你想建立一个物理引擎,你必须了解物理学。物理学很复杂。即使你是一个非常擅长EF或SQL编程的人,这也不会帮助你构建物理引擎。了解物理领域并能够制作其域模型,然后再实现是关键。
如果你想真正感受域模型和实现之间的区别,请查看这个链接。在你开始任何实现之前,这个领域可能会让你大吃一惊。
同时,请查看这篇有关使用DDD建模实体的文章。
编辑
这篇文章解释了NHibernate和EntityFramework在领域建模方面的不同之处。