域驱动设计API问题

时间:2011-08-26 21:35:34

标签: c# .net domain-driven-design

我是DDD的新手,我正在开展我的第一个项目,即在线高尔夫郊游注册过程。我的要求非常简单。用户注册外出,可以选择添加四人组。他们还可以赞助一个带有消息和其他一些东西的漏洞,但我想先把我们的四个东西哈希。

所以,我的第一个虽然我的聚合包含一个注册实体,四个值对象(包含团队名称和4个玩家值对象)。

在设计api时,我正在考虑以下伪代码:

Registration reg = new Registration();

Foursome foursome = reg.CreateFoursome("My Team");

foursome.Player1.Assign("John Doe", 5, ShirtSize.XL);

reg.Register();

我的问题是,聚合的一个内部组件正在暴露给客户端代码,所以我是否为问题打开了自己?这个简单设计或替代apis的任何缺陷?

任何帮助都会很棒,因为我现在处于分析瘫痪状态!

感谢

2 个答案:

答案 0 :(得分:1)

让我们从Aggregate definition开始:

  

一组关联对象,被视为一个单元   数据更改的目的。外部引用仅限于一个   聚合的成员,指定为根。一组一致性   规则适用于Aggregate的边界。

聚合是一组您不希望多个用户同时编辑的对象,因为它可以破坏域不变量。 Aggregate也是一个生命周期单元。如果不知道这些不变量,一致性和生命周期规则是什么,就很难回答你的问题。在同一个注册上创建两个四人组会不好? Foursome与未分配的Player1会无效/不一致吗?不会在注册对象上调用Register会'腐败'吗?如果其中一个答案为真,那么你不应该像那样暴露你的对象。此代码应隐藏在您的聚合中。

它看起来像Foursome不是Value Object,因为它是可变的。它可能是一个应该由注册聚合根保护的实体。

// PlayerInfo is a value object
public static Registration CreateNew(String foursomeName, PlayerInfo player1, ...) {
    if (foursomeName == null) {
        throw new ArgumentNullException("foursomeName");
    }
    if (player1 == null) {
        throw new ArgumentNullException("player1");
    }

    Registration reg = new Registration();

    Foursome foursome = reg.CreateFoursome("My Team");

    foursome.Player1.Assign(player1);

    if(player2 != null) {
        foursome.Player2.Assign(player2);
    }
    reg.Register();

    // return consistent and valid Registration instance
    return reg;
}

同样,这可能不是您想要的,它实际上取决于您的域模型。也许你的Aggregate root应该是像FoursomeRegistartion这样的实体。如果玩家可以在Foursome / Registration边界之外存在,那么玩家可能会聚集在一起。正如其他人所说,第一次很难让模型正确。有第一次实施和重构。

答案 1 :(得分:0)

第一次拍摄也不错。在开始设计时不要过于依赖细节,这一点很重要。您花多少时间担心设计的稳健性主要是项目重要性的一个因素。您将在构建时不断学习,随着时间的推移,您的旧代码将需要重构以启用新的详细信息。

比如说,我认为你的FourSome课程有四名球员。您是否可以使用具有“大小”约束的Team类,以便Players集合可以限制为该数量的玩家?是否应该有Player类(或者可能是Player1的类型?)?

这些问题的答案将对您系统的可扩展性产生影响。

我鼓励您将每个场景编写成测试(您也可以使用用户故事或用例,但开发人员喜欢编写代码),并在编写测试时填写注册,播放器和四人/团队类实现使测试成功。在扩展系统时,您的测试将会发生变化,您的设计也会发生变化。

后期增加1:

域驱动设计旨在开发应用程序将使用的类和数据结构,以便“模拟”问题域。在您的情况下,您正在使用高尔夫郊游注册系统。因此,当您考虑可能构成此类系统的实体时,您可以描述团队队长如何通过提供他的注册来注册他/她的团队(包括其他玩家)。注册可能是针对一个事件,事件本身可能有详细信息,如组织者,赞助商等。如您所见,每个“大写”名称都成为您的实体(类)。至少对于你的设计的初稿。当您发现有关类之间关系的更多信息时,尤其是它们如何交互(将玩家添加到团队中)时,您将充实您班级的方法。

在此过程中,您可能会无意中引入设计缺陷。例如,从技术上讲,FourSome是一种仅限于四名玩家的团队。从Team派生一个类并设置四个玩家的限制是否有意义,或者对团队施加约束是否有意义?这是一个由......您的业务规则和您决定的设计决策。采取一种方法而不是另一种方法是错误的吗?时间会证明,因为你需要不断重构才能扩展系统。

在设计过程中,您会发现许多模式可能会使您的设计过程更加轻松,但新设计师通常没有经验来识别何时使用它们。如果你这样做,请向你致敬。在您第一次设计时,您将找不到完美的设计。我仍然回顾(现在15年)我认为很棒的设计,并在我年轻的活力中摇头。

您应该(自己或纸上)描述您的问题。强调名词。他们是你的候选班级。讲述每个用户与系统交互的故事,动词应该让您开始了解每个类的方法。避免使用注册来完成所有工作,但将类的责任分开到适当的位置。例如,您可以将球员添加到球队,或者您可以让球员将自己添加到球队。确定责任所在的位置应由SRP指导(但不是由其指定),以及其他设计指南。

最后,设计中没有正确的答案。我可以根据我丰富的设计经验告诉你,但我认为应该是有限的高尔夫体验,但最终你的最佳设计取决于功能,范围和设计目标(如可扩展性)。从你最好的镜头开始,针对它编写测试,你的设计缺陷将在你知道它之前出现。 :d

修订后2:

我认为你正在阅读Eric Evan的指导。我不相信他说你不能从四人中揭露玩家。