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 的 交易脚本 与 Domain Model 简要解释了这两种模式,我认为它们与 DDD 相关。
I'll give you a simple example of real production code:
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
}
Whenever I want to bind a person to a group, I can just do person.addToGroup(group)
The procedural code would be something like this, on your controller:
def m = Membership.findByPersonAndGroup(person, group)
if (!m) {
m = new Membership()
person?.addToMemberships(m)
group?.addToMemberships(m)
m.save()
}
At first sight, you can say that you can wrap that in a function and you are good to go.
But the advantage of rich domain design IMHO is that it is closer with the way you think, thus closer to rationalize on. In this particular example, I just want to add a person to a group, and the code will read just that.
This is a short example like you asked, but it's easy to expand this example and see that you can build complex interactions with proper domain modeling.
You can also see Martin Fowler's Transaction Script vs Domain Model for a brief explanation of these two patterns, which I consider related to DDD.
I think that nobody have done that kind of comparison and if it had been, then it wouldn't be small. Domain Driven Design tries to solve complexity and a simple example doesn't contain complexity.
这是一个原则上领域驱动设计应该是什么样子的示例。假设您有一个 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。这与数据库表结构不太匹配,因此出现“阻抗不匹配”,或者用外行人的话来说,关系模型和对象模型之间的布局差异。
在领域驱动设计中,我应该能够做到这一点:
Person person = new Person();
// set each property to something
Database.Save(person);
现在,人员对象已保存。我可以像这样检索它:
Person databasePerson = Database.Get<Person>(idOfPerson);
它将返回我的 Person 对象,就像我保存它之前一样。这样,我根本不关心数据库如何保存它,也不担心阻抗不匹配。我只是保存它并根据需要检索它。
This doesn't exactly answer your question, but I see the opposite of domain-driven design as database-driven design. In database-driven design, the database schema is created first, and then you create your classes with full knowledge of what the schema looks like. The advantage is that you have a better understanding of what's going on 'under the hood', and minimize the effects of impedance mismatch. However, the downside is that the database schema, because it's relational rather than object-oriented, doesn't translate very to objects (for example, there's no concept of a collection in relational databases).
In domain-driven design, in theory you create your data objects just like you would any other class, and treat the database as simply a persistence layer. In Layman's terms, the database is only a storage container and you don't care HOW the objects are stored, only that they are stored somehow. This eliminates the impedance mismatch and you have one less thing to worry about. In practice, however, you still have to be aware of how the objects are stored, and there can be performance issues when the ORM you're using is trying to spit out a complex SQL query.
Edit:
Here's an example of what domain-driven design should be like, in principle. Let's say you have a Person class, like so (in 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; }
}
Now, in a relational database, this will probably translate to 3 tables, a Person table, Address table, and Company table, with a bunch of relationships between them. However, this is vastly different than how the programmer sees this object. The programmer sees it as an instance of a Person object with 4 parameters, one of which is a ICollection. This doesn't match up very well with the database table structure, hence the 'impedance mismatch', or in Laymen's terms, a difference in layout between the relational model and object model.
In domain-driven design, I should be able to do this:
Person person = new Person();
// set each property to something
Database.Save(person);
Now, the person object is saved. I can retrieve it like so:
Person databasePerson = Database.Get<Person>(idOfPerson);
And it'll return my Person object, just like how it was before I saved it. This way, I'm not concerned at all with how the databse is saving it, or worry about the impedance mismatch. I simply save it and retrieve it as needed.
This is all in theory though. In practice, you'll probably have to manually specify the 'mapping', or how the classes know which table/column in the database to get data from. It can get pretty complex when you're trying to map to more complex types such as dictionaries and other ADTs, and also when you're trying to pull data from multiple tables into one class.
发布评论
评论(3)
我会给你一个真实生产代码的简单示例:
Person.groovy:
Membership.groovy:
每当我想将一个人绑定到一个组时,我可以这样做person.addToGroup(group)
在你的控制器上,程序代码将是这样的:
乍一看,你可以说你可以将其包装在一个函数中,然后就可以开始了。
但恕我直言,富域设计的优点是它更接近你的思维方式,从而更接近合理化。在这个特定的示例中,我只想将一个人添加到一个组中,代码将读取该内容。
正如您所要求的,这是一个简短的示例,但是很容易扩展此示例并看到您可以使用适当的域建模来构建复杂的交互。
您还可以查看 Martin Fowler 的 交易脚本 与 Domain Model 简要解释了这两种模式,我认为它们与 DDD 相关。
I'll give you a simple example of real production code:
Person.groovy:
Membership.groovy:
Whenever I want to bind a person to a group, I can just do person.addToGroup(group)
The procedural code would be something like this, on your controller:
At first sight, you can say that you can wrap that in a function and you are good to go.
But the advantage of rich domain design IMHO is that it is closer with the way you think, thus closer to rationalize on. In this particular example, I just want to add a person to a group, and the code will read just that.
This is a short example like you asked, but it's easy to expand this example and see that you can build complex interactions with proper domain modeling.
You can also see Martin Fowler's Transaction Script vs Domain Model for a brief explanation of these two patterns, which I consider related to DDD.
我认为没有人做过这样的比较,如果有的话,那么它的影响也不会小。领域驱动设计试图解决复杂性,而简单的示例并不包含复杂性。
也许领域驱动设计分步会给你一些答案。
I think that nobody have done that kind of comparison and if it had been, then it wouldn't be small. Domain Driven Design tries to solve complexity and a simple example doesn't contain complexity.
Maybe Domain Driven design Step by Step will give you some answers.
这并不能完全回答您的问题,但我认为领域驱动设计与数据库驱动设计相反。在数据库驱动设计中,首先创建数据库模式,然后在充分了解该模式的情况下创建类。优点是您可以更好地了解“幕后”发生的情况,并最大限度地减少阻抗不匹配的影响。然而,缺点是数据库模式,因为它是关系型的而不是面向对象的,所以不能很好地转换为对象(例如,关系数据库中没有集合的概念)。
在领域驱动设计中,理论上,您可以像创建任何其他类一样创建数据对象,并将数据库视为简单的持久层。通俗地说,数据库只是一个存储容器,您不关心对象如何存储,只关心它们以某种方式存储。这消除了阻抗不匹配,您就少了一件需要担心的事情。然而,在实践中,您仍然必须了解对象的存储方式,并且当您使用的 ORM 尝试输出复杂的 SQL 查询时,可能会出现性能问题。
编辑:
这是一个原则上领域驱动设计应该是什么样子的示例。假设您有一个 Person 类,如下所示(在 C# 中):
现在,在关系数据库中,这可能会转换为 3 个表:Person 表、Address 表和 Company 表,它们之间有一堆关系。然而,这与程序员看待这个对象的方式有很大不同。程序员将其视为具有 4 个参数的 Person 对象的实例,其中之一是 ICollection。这与数据库表结构不太匹配,因此出现“阻抗不匹配”,或者用外行人的话来说,关系模型和对象模型之间的布局差异。
在领域驱动设计中,我应该能够做到这一点:
现在,人员对象已保存。我可以像这样检索它:
它将返回我的
Person
对象,就像我保存它之前一样。这样,我根本不关心数据库如何保存它,也不担心阻抗不匹配。我只是保存它并根据需要检索它。但这都是理论上的。在实践中,您可能必须手动指定“映射”,或者类如何知道从数据库中的哪个表/列获取数据。当您尝试映射到更复杂的类型(例如字典和其他 ADT)时,以及当您尝试将多个表中的数据提取到一个类中时,它可能会变得相当复杂。
This doesn't exactly answer your question, but I see the opposite of domain-driven design as database-driven design. In database-driven design, the database schema is created first, and then you create your classes with full knowledge of what the schema looks like. The advantage is that you have a better understanding of what's going on 'under the hood', and minimize the effects of impedance mismatch. However, the downside is that the database schema, because it's relational rather than object-oriented, doesn't translate very to objects (for example, there's no concept of a collection in relational databases).
In domain-driven design, in theory you create your data objects just like you would any other class, and treat the database as simply a persistence layer. In Layman's terms, the database is only a storage container and you don't care HOW the objects are stored, only that they are stored somehow. This eliminates the impedance mismatch and you have one less thing to worry about. In practice, however, you still have to be aware of how the objects are stored, and there can be performance issues when the ORM you're using is trying to spit out a complex SQL query.
Edit:
Here's an example of what domain-driven design should be like, in principle. Let's say you have a Person class, like so (in C#):
Now, in a relational database, this will probably translate to 3 tables, a Person table, Address table, and Company table, with a bunch of relationships between them. However, this is vastly different than how the programmer sees this object. The programmer sees it as an instance of a Person object with 4 parameters, one of which is a
ICollection
. This doesn't match up very well with the database table structure, hence the 'impedance mismatch', or in Laymen's terms, a difference in layout between the relational model and object model.In domain-driven design, I should be able to do this:
Now, the person object is saved. I can retrieve it like so:
And it'll return my
Person
object, just like how it was before I saved it. This way, I'm not concerned at all with how the databse is saving it, or worry about the impedance mismatch. I simply save it and retrieve it as needed.This is all in theory though. In practice, you'll probably have to manually specify the 'mapping', or how the classes know which table/column in the database to get data from. It can get pretty complex when you're trying to map to more complex types such as dictionaries and other ADTs, and also when you're trying to pull data from multiple tables into one class.