DDD方法可在何处执行业务规则而无需汇总?

时间:2019-01-02 22:25:17

标签: oop design-patterns architecture domain-driven-design

DDD的新手我有一个简单的案例,我想使用DDD方法进行建模

2个实体StudentCourse

学生的相关属性是StudentId和预算

课程的相关属性是CourseId和Price

学生和课程是可以独立存在并具有自己生命周期的实体

业务要求:

1)学生可以预订一门课程(“学生表”的课程编号是fk)

2)仅当用户的预算高于或等于课程价格时,学生才能预订课程。

3)课程价格的变化不会影响已经预订课程的学生。

4)当学生预订该课程时,其预算保持不变(可能在课程结束时更改)

5)可以修改学生预算,设置不同的金额,但新的金额必须高于或等于用户预订课程的价格。
设置较低的值将引发运行时错误。

如何按照域驱动设计对这种简单案例进行建模?在哪里执行这两个业务规则(第2点和第5点)?

由于课程可以不存在学生而存在,因此我无法定义汇总,其中学生是根实体,课程是其子实体。我可以吗?

但是同时,在我看来,第5点定义的业务规则是不变的。是吗?

那么在哪里以及如何应用此规则?

我尝试了一种服务方法,可以使用第一个简单规则(第2点),但不能使用第5点描述的规则

var student = studentRepository.Get(srtudentId);
var course = courseRepository.Get(courseId)

var studentService = new StudentService();

studentService.SubScribeStudentToCourse(student, course);

studentRepository.Update(student);


StudentService.ChangeStudentBudget(student, 100000);

studentRepository.Update(student);  

当我用新的预算更新学生时,其他人可以更改课程价格,从而导致学生预算不一致

public class StudentService
{
    SubScribeStudentToCourse(Studen student, Course course)
    {
        if (studentt.Budget >= course.Price)
        {
            student.CourseId = course.CourseId
        }
    }

    ChangeStudentBudget( Student student, decimal budgetAmount)
    {
        if (student.CourseId != null)
        {
            var studentCourse = courseRepository.Get(student.CourseId);
            if ( studentCourse.Price <= budgetAmount)
            {
                student.Budget = budgetAmount;
            }
            else
            {
                throw new Exception("Budget should be higher than studentCourse.Price");
            }
        }
    }
}

3 个答案:

答案 0 :(得分:2)

假设情景通常很难评论,但我将添加ZAR0.02:)

您将同时拥有Student Course聚合根。如果需要与定义的另一方的关系,则存储ID列表或代表另一方的值对象。

要强制执行某些不能重叠的规则,可以更简单地说明Student上的预算状态。例如,如果课程未处于BudgetApproved状态,则无法添加到课程。为了更改预算,您首先需要将状态更改为“预算”。这样,您将引入更多不同的步骤,从而可以更好地控制不变量。

关于改变价格的另一个说明。无论如何,这些事情可能会在“引用”的基础上起作用。一旦“接受”报价,价格的任何变化都是不相关的,除非存在“错误”或“遗漏”,这些错误或“遗漏”可以并且应该使用某些业务流程来处理,或者,如果未在系统中定义,则超出带。 Order可能是Cancelled或“被遗弃”,然后启动了其他程序,例如报销。

答案 1 :(得分:1)

第5点是另一个验证规则。但是,如果可以修改课程价格,则不仅要修改学生预算,还必须在那里检查规则。

它不是不变的。不变只涉及一个集合。您有两个聚合。

这个问题听起来像我已经回答了。

答案 2 :(得分:0)

除非是一个非常重要的情况,否则您的汇总最终必须是一致的,而不是强一致性。如果是这样,则考虑使用Saga,或在一项交易中对其进行更新。您在这里应该做的很简单:StudentService.SubscribeTo()和CourceService.Enroll()。这2种方法应在2个不同的事务中发生。首先,在StudentService.SubscribeTo内部,从持久性中获取学生和课程模型,然后调用student.SubscribeTo(course)。操作完成后,您引发学生assignedToCourse域事件,然后StudentDomainEventsHandler捕获该事件,并调用CourceService.Enroll()从持久性中获取学生和课程模型,然后调用course.Enroll(student)。