DDD-如何处理应用程序层中的获取或创建逻辑?

问题描述 投票:0回答:1

我在域层中有一个DailyReport实体。该对象中包含一些字段:

  • reportId
  • userId
  • date
  • [tasks-收集用户在特定日期所做的事情;
  • mood-用户在一整天的感觉;

此外,我的应用程序服务中有一些方法:

  • DailyReportService::addTaskToDailyReport
  • DailyReportService::setUserMoodInDailyReport

事实是,这两种方法都要求更早地创建DailyReport或在函数执行期间创建。如何处理这种情况?

我找到2个解决方案:

1在方法分派之前创建新的DailyReport对象,然后将reportId传递给它们:

//PHP, simplified
public function __invoke() {
    $taskData = getTaskData();

    /** @var $dailyReport DailyReport|null **/
    $dailyReport = $dailyReportRepository->getOneByDateAndUser('1234-12-12', $user);

    //there were no report created today, create new one
    if($dailyReport === null) {
        $dailyReport = new DailyReport('1234-12-12', $user);
        $dailyReportRepository->store($dailyReport);
    }

    $result = $dailyReportService->addTaskToDailyReport($taskData, $dailyReport->reportId);

    //[...]

}

这需要向我的控制器添加更多业务逻辑,我想避免。


2:在方法中验证DailyReport存在,并根据需要创建一个新的:

//my controller method
public function __invoke() {
    $taskData = getTaskData();
    $result = $dailyReportService->addTaskToDailyReport($taskData, '1234-12-12', $user);

    //[...]
}


//in my service:

public function addTaskToDailyReport($taskData, $date, $user) {

    //Ensure that daily report for given day and user exists:
    /** @var $dailyReport DailyReport|null **/
    $dailyReport = $dailyReportRepository->getOneByDateAndUser();

    //there were no report created today, create new one
    if($dailyReport === null) {
        $dailyReport = new DailyReport($date, $user);
        $dailyReportRepository->store($dailyReport);
    }

    //perform rest of domain logic here
}

这降低了我的UI层的复杂性,并且没有在应用程序层之上公开业务逻辑。


也许这些示例比DDD更像CRUD,但我想以更简单的方式公开我的用例之一。

在这种情况下,应使用哪种解决方案?有没有更好的方法来处理DDD中的“获取或创建”逻辑?

php domain-driven-design software-design business-logic business-rules
1个回答
0
投票

我不确定这是否是您想听到的答案,但基本上我认为您正在处理偶然的​​复杂性,并且您正在尝试解决错误的问题。

在继续之前,我会强烈建议您考虑以下问题:

  1. [如果某人两次提交相同的报告会发生什么
  2. [如果某人两次不同地提交报告会发生什么,但是在第二次中,报告会略有不同?
  3. 两次存储来自同一个人的同一份报告有什么影响?

上述问题的答案应指导您做出决定。

重要:另外,请注意,您上面的两个方法都有一个小窗口,其中两个并发请求都可以成功存储报告。

根据个人经验,我建议:

  1. 如果没有重复项不是一个大问题(例如,您可能有一个手动运行或经常自动执行以清除重复项的脚本),那么请按照您的选择1进行操作。这还不错,而且不会出现人为错误。应该可以。
  2. 如果重复出现问题,请在提交报告后使进程异步运行,并尝试查找重复项。然后根据您的域专家的需求进行处理(例如,可能删除重复项,如果更新了,则删除旧的或标记为人为决定)
  3. [如果这是业务中不变级别约束的一部分(尽管我高度怀疑它是因为我们正在谈论报告),并且在任何时候都没有应该有两个报告,那么应该有一个汇总来执行此操作。也许这是UserMonthlyReport或其他,您可以在运行时强制执行。当然,这更复杂,并且可能需要做更多的工作,但是,如果有一个不变量的商业案例,那么这就是您应该做的。 (再次,我怀疑报告是否需要它,但是我在这里以护理报告为例,或为将来的读者编写了它。)>
© www.soinside.com 2019 - 2024. All rights reserved.