【问题标题】:Is there a rich domain model example? [closed]是否有丰富的域模型示例? [关闭]
【发布时间】:2010-12-12 10:45:06
【问题描述】:

我正在寻找一个简单的示例来说明使用富域模型的好处。理想情况下,我想要之前和之后的代码清单(应该尽可能短)。

之前的代码清单应该显示使用贫乏的域模型解决的问题,以及许多相当程序化的服务层代码,而之后的代码清单应该显示使用丰富的面向对象的域来解决相同的问题型号。

理想情况下,代码清单应该使用 Java 或 Groovy,但任何非常相似的内容(例如 C#)都可以。

【问题讨论】:

  • 不幸的是,很难用简短的回答来描述这些好处。如果您正在编写一个包含大量行为的系统,而不仅仅是插入/更新/删除,那么您可能会受益于将逻辑封装在一组类(您的域模型)中。在您拥有足够大的解决方案并且您的域逻辑足够复杂之前,您可能不会看到这些好处。在这种情况下,将您的域逻辑封装在一个地方是非常好的。

标签: c# java domain-driven-design domain-model


【解决方案1】:

我给你一个真实生产代码的简单例子:

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 ScriptDomain Model 对这两种模式的简要说明,我认为这与 DDD 有关。

【讨论】:

    【解决方案2】:

    我认为没有人做过这种比较,如果做过,那就不会小了。领域驱动设计试图解决复杂性,一个简单的例子不包含复杂性。

    也许Domain Driven design Step by Step会给你一些答案。

    【讨论】:

      【解决方案3】:

      这并不能完全回答您的问题,但我认为域驱动设计的反面是数据库驱动设计。在数据库驱动设计中,首先创建数据库模式,然后在完全了解模式的情况下创建类。优点是您可以更好地了解“幕后”发生的事情,并将阻抗失配的影响降至最低。但是,缺点是数据库模式,因为它是关系型而不是面向对象的,不能很好地转换为对象(例如,关系型数据库中没有集合的概念)。

      在域驱动设计中,理论上您可以像创建任何其他类一样创建数据对象,并将数据库视为简单的持久层。用 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。这与数据库表结构不太匹配,因此是“阻抗不匹配”,或者用通俗的话来说,是关系模型和对象模型之间的布局差异。

      在领域驱动设计中,我应该能够做到这一点:

      Person person = new Person();
      // set each property to something
      Database.Save(person);
      

      现在,person 对象被保存。我可以这样检索它:

      Person databasePerson = Database.Get<Person>(idOfPerson);
      

      它会返回我的Person 对象,就像我保存它之前一样。这样,我根本不关心数据库如何保存它,或者担心阻抗不匹配。我只是保存它并根据需要检索它。

      不过,这都是理论上的。在实践中,您可能必须手动指定“映射”,或者类如何知道从数据库中的哪个表/列获取数据。当您尝试映射到更复杂的类型(例如字典和其他 ADT)以及尝试将多个表中的数据提取到一个类中时,它可能会变得非常复杂。

      【讨论】:

      • 我不认为这是一个富域模型的例子,因为你描述的域不包含任何行为。
      • 这不是富域。在富域中,您可能不会有任何 setter,或者只有少数。
      • 您在谈论对象关系映射,这是一个完全不同的概念。您的 Person 类包含一个数据结构,仅此而已。您需要方法和封装(数据和实现隐藏)将其转换为真实对象。
      猜你喜欢
      • 1970-01-01
      • 2014-01-05
      • 2011-12-03
      • 2014-06-12
      • 2023-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-06
      相关资源
      最近更新 更多