我正在寻找一个简单的例子来说明使用富域模型的好处。理想情况下,我想要一个前后代码列表(应该尽可能短)。
之前的代码清单应该显示使用贫血域模型解决的问题,以及许多相当程序化的服务层代码,后面的代码清单应该显示使用丰富的面向对象的域解决相同的问题模型。
理想情况下,代码清单应该是Java或Groovy,但任何相似的东西(例如C#)都可以。
答案 0 :(得分:3)
我将为您提供一个真实生产代码的简单示例:
<强> Person.groovy:强>
List addToGroup(Group group) {
Membership.link(this, group)
return groups()
}
<强> Membership.groovy:强>
static Membership link(person, group) {
def m = Membership.findByPersonAndGroup(person, group)
if (!m) {
m = new Membership()
person?.addToMemberships(m)
group?.addToMemberships(m)
m.save()
}
return m
}
每当我想将一个人绑定到一个组时,我就可以做 person.addToGroup(group)
程序代码就像这样,在你的控制器上:
def m = Membership.findByPersonAndGroup(person, group)
if (!m) {
m = new Membership()
person?.addToMemberships(m)
group?.addToMemberships(m)
m.save()
}
乍一看,你可以说你可以将它包装在一个函数中,你就可以了。
但丰富的域名设计恕我直言的优势在于它与您的思维方式更接近,因此更接近合理化。在这个特定的例子中,我只想将一个人添加到一个组中,代码将只读取它。
这是一个简短的例子,就像你问的那样,但很容易扩展这个例子,看看你可以通过适当的域建模来构建复杂的交互。
您还可以看到Martin Fowler的Transaction Script vs Domain Model,以简要解释这两种模式,我认为这些模式与DDD有关。
答案 1 :(得分:3)
也许Jimmy Bogard的这个演讲包含了你要求的内容
https://github.com/jbogard/presentations/tree/master/WickedDomainModels
答案 2 :(得分:2)
我认为没有人做过那种比较,如果是的话,那就不会那么小了。 Domain Driven Design试图解决复杂性,一个简单的例子不包含复杂性。
也许Domain Driven design Step by Step会给你一些答案。
答案 3 :(得分:-5)
这并不能完全回答您的问题,但我认为域驱动设计与数据库驱动设计相反。在数据库驱动的设计中,首先创建数据库模式,然后在完全了解模式外观的情况下创建类。优点是您可以更好地了解“引擎盖下”发生的情况,并最大限度地减少阻抗不匹配的影响。但是,缺点是数据库模式,因为它是关系而不是面向对象,不会很好地转换为对象(例如,关系数据库中没有集合的概念)。
在域驱动设计中,理论上您可以像创建任何其他类一样创建数据对象,并将数据库简单地视为持久层。在Layman的术语中,数据库只是一个存储容器,您不关心对象是如何存储的,只是它们以某种方式存储。这消除了阻抗不匹配,您可以少担心一件事。但是,实际上,您仍然需要了解对象的存储方式,并且当您使用的ORM尝试吐出复杂的SQL查询时,可能会出现性能问题。
修改强>
原则上,这是一个域驱动设计应该是什么样的例子。假设你有一个Person类,就像这样(在C#中):
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
public ICollection<Person> Relatives { get; set; }
public Company Employer { get; set; }
}
现在,在关系数据库中,这可能会转换为3个表,一个Person表,Address表和Company表,它们之间有很多关系。但是,这与程序员看到此对象的方式大不相同。程序员将其视为具有4个参数的Person对象的实例,其中一个参数是ICollection
。这与数据库表结构不匹配,因此“阻抗不匹配”,或者在Laymen的术语中,是关系模型和对象模型之间布局的差异。
在域驱动设计中,我应该能够做到这一点:
Person person = new Person();
// set each property to something
Database.Save(person);
现在,人物对象被保存。我可以像这样检索它:
Person databasePerson = Database.Get<Person>(idOfPerson);
它将返回我的Person
对象,就像我保存它之前的那样。这样,我完全不关心数据库如何保存它,或者担心阻抗不匹配。我只需保存并根据需要检索它。
但这完全是理论上的。实际上,您可能必须手动指定“映射”,或者类如何知道数据库中的哪个表/列来从中获取数据。当您尝试映射到更复杂的类型(如字典和其他ADT)时,以及当您尝试将数据从多个表中提取到一个类中时,它会变得非常复杂。