首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >对于在DDD (领域驱动的设计)中谁应该开始一个动作,有一个非常基本的疑问。

对于在DDD (领域驱动的设计)中谁应该开始一个动作,有一个非常基本的疑问。
EN

Software Engineering用户
提问于 2023-03-25 08:36:38
回答 3查看 100关注 0票数 0

当我读到DDD的时候,人们总是说它是关于行为的,用另一种方式说,动作比可以执行的。

我怀疑该由谁来发起行动。

假设我有一个关于订单的有界上下文(BC)。举个例子,我只讲几条规则。

  • 雇员收到订单。
  • 员工创建订单。
  • 员工将在订单中添加行。

通常,在我看到的示例中,是在创建订单的应用层中,然后在数据库中持久化,如下所示:

代码语言:javascript
复制
public class CreateOrderApplicationService
{
    public Order CreateOrder(long paramIdEmployee)
    {
        Order myOrder = Order.Create(paramIdEmployee);
        _repository.Add(myOrder);
        _repository.Commit();
    }
}

但是,我认为订单本身是不能创建的,事实上,在规则和无处不在的语言中,说员工收到订单,员工创建订单……依此类推,或者至少它暗示着它总是一个人,一个用户,一个雇员或另一种人做某事。或者系统的另一个进程,可以看作是另一种用户。

因此,从这个角度来看,我认为另一个解决办法可能是:

代码语言:javascript
复制
public class CreateOrderApplicationService
{
    public Order CreateOrder(long paramIdEmployee)
    {
        Employee myEmpolyee = _repository.GetEmployee(paramIdEmployee);
        Order myOrder = myEmpolyee.CreateOrder();
        _repository.Commit();
    }
}

public class Employee
{
    long Id;
    List<Order> Orders;

    public Order CreateOrder()
    {
        Order myOrder = Order.Create(Id);
        Orders.Add(myOrder);
        return Order;
    }
}

注意:这里,我从order存储库中获得了employee,因为如果我没有错,通常的做法是为每个有界的上下文创建一个存储库,因此在我的有界上下文中需要一个employee。无论如何,该示例试图显示,我从存储库(无论从哪一个存储库中)获取员工来执行创建订单的操作。

在这种情况下,员工只是将订单的创建委托给order实体,但它是操作的起点。

但是在这个解决方案中,确实,所有的行为和所有有界的上下文都需要一个人实体,所有的行为都将通过实体人来完成,这似乎是一个奇怪的解决方案。但从另一个角度来看,似乎很直观的是,任何行动都是由一个人执行的,而在无处不在的语言中,据说是雇员创建了订单,而不是说订单是创建的(一般情况下)。

所以,对于那些从DDD开始的人来说,可能有点混乱,因为取决于使用无处不在的语言的方式,解决方案可能是不同的,或者导致以不正确的方式思考,或者导致使用技术解决方案,在这种情况下,谁开始行动,从专家的方式,而不是技术人员,只是关于问题解决的专家。

总之,我想知道通过用户启动每个操作的解决方案是否是个坏主意。

谢谢。

EN

回答 3

Software Engineering用户

发布于 2023-03-25 11:37:23

DDD并不规定这样的细节,即使它会,它也不是你必须盲目遵循的“法律”。我建议不要再去想一些教条会说些什么,而应该多想想什么才是最有意义的。代码行

代码语言:javascript
复制
    Order myOrder = Order.Create(paramIdEmployee);

Order构造函数只需要雇员ID时,就可以了,并且

代码语言:javascript
复制
    Employee myEmployee = _repository.GetEmployee(paramIdEmployee);
    Order myOrder = myEmployee.CreateOrder();

当订单创建所需的不仅仅是员工的id,而是必须首先检索的Employee对象的更多数据时,就可以了。当整个用例需要一个带有新添加的order对象的对象myEmployee时,这也是可以的。

但是,当您在订单创建之后放弃myEmployee时,这就变得不必要地过于复杂了。首先从repo查询employee对象(这可能会导致数据库或网络查询)也不是很有效,只是为了传递您手头已有的ID。

回到你关于“谁开始行动”的问题上--我认为要做到这一点,你必须后退一步,看看一个完整的用例。例如,让我们假设这是一些GUI应用程序,它的开头是一个真实的人(比如一个公司的雇员)坐在电脑前,试图“创建一个真正的订单”。然后,当该用户按下UI中的某个按钮时,这将从表示层启动一条消息,该消息可能通过其他层传递,并最终调用CreateOrderApplicationService。由于用户以某种方式连接到系统,因此在调用CreateOrderApplicationService时,可能已经存在一个employee对象,该对象可以传递到服务调用中,然后如下所示:

代码语言:javascript
复制
public class CreateOrderApplicationService
{
    public Order CreateOrder(Employee employee)
    {
        Order myOrder = employee.CreateOrder();
        _repository.AddOrder(myOrder);
        _repository.Commit();
    }
}

但是详细地说,整个用例的工作方式可能不同,在创建订单时,employee对象可能并不总是在手上,在这种情况下,简单的Order.Create方法可能是最简单(因此也是很好)的解决方案。

票数 1
EN

Software Engineering用户

发布于 2023-03-25 15:49:42

在DDD中,我们并不是在模拟现实世界。该模型应该能够解决手头的业务问题。虽然这确实应该使用与领域专家协作创建的语言来完成,但这并不意味着领域概念之间的关系应该完全符合现实!

在专注于订单处理的模型(BC)中,我们真的需要员工集合吗?或者,仅仅知道是哪个员工创建了这个订单就足够了吗?在这种情况下,一个简单的employeeId就足够了。

所以,虽然您是正确的,在现实世界中,订单不会自己创建,而在为解决特定业务问题而创建的模型中,称为Order.Create(employeeId)的工厂方法是完全可以接受的。

票数 1
EN

Software Engineering用户

发布于 2023-03-26 04:20:09

据我所知,这里没有很好的权威答案.

我可以认为,订单本身是无法创建的,事实上,在规则和无处不在的语言中,据说员工收到订单,员工创建订单……

一个有趣的视角是由Udi大汉编写的:

顾客不是凭空出现的。

他当时的立场是,你会用你已经知道的东西来创造新的东西。

按照他描述的模式,您将得到雇员的内存表示,然后将创建订单并将其添加到适当集合的问题委托给该代码。

尽管如此,我还没有发现像其他DDD作者/影响者/实践者一样表达类似的想法。Udi似乎是在他自己的岛上。

票数 0
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/444691

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档