首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >DDD执行业务规则

DDD执行业务规则
EN

Software Engineering用户
提问于 2019-01-03 08:11:17
回答 2查看 1.1K关注 0票数 0

对于DDD,我有一个简单的案例,我想使用DDD方法建模

2实体-学生和课程

学生的相关财产是StudentId和预算

当然,相关的属性是CourseId和价格

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

业务需求:

1)学生可以预定一门课程(CourseId是表示学生表的fk )

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

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

4)当学生预定课程时,他的预算保持不变(可能在课程结束后有所改变)

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

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

由于一个课程可以在没有学生的情况下存在,所以我不能定义聚合,其中学生是根实体,课程是子实体。我能?

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

那么,在哪里以及如何应用这些规则呢?

我尝试了一种服务方法,可以适用于第一个简单规则(第2点),但对于第5点描述的规则却失败了。

代码语言:javascript
复制
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);  

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

代码语言:javascript
复制
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");
            }
        }
    }
}
EN

回答 2

Software Engineering用户

回答已采纳

发布于 2019-01-03 09:18:48

这两种业务规则都是对“学生”实体的限制。这意味着它们可以由Student实体本身强制执行,也可以由与您一样的服务类强制执行。

关于预算变更的规则的编写方式

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

没有说明应该考虑哪个课程的价格(如果在预订课程和改变预算之间的价格发生了变化)。这是你应该要求澄清的事情。

如果新的预算必须足以支付当前的课程价格,那么您当前的实现几乎是好的(您错过了在预定课程之前更改预算的情况)。

如果新的预算必须包括在预订时的课程价格,你将不得不记住这个数额。这可以是在“学生”实体中,也可以是“课程实体”保存了随时间变化的价格记录,“学生实体”记录了课程预订后的情况。

票数 2
EN

Software Engineering用户

发布于 2019-01-03 19:53:52

过度使用服务是贫血模式的一个明显标志。您的系统可以非常简单地建模:

代码语言:javascript
复制
class Student
{
    private studentId;

    private budget;

    private registration;

    Book( Registration registration )
    {
        if( registration.Price > this.budget )
            throw;

        this.registration = registration;
    }

    ChangeBudget( amount )
    {
        if( this.registration && this.registration.Price > amount )
            throw;

        this.budget = amount;
    }
}


class Course
{
    private courseId;

    private price;

    // Factory Method
    OpenRegistration( offers )
    {
        price = ; // do something to calculate new price

        return new Registration( this.courseId, price );
    }
} 

// Value Object
class Registration
{
    public CourseId { get; }

    public Price { get; }

    Registration( courseId, price )
    {
        CourseId = courseId;
        Price = price;
    }
}

然后在你的BookCourseCommandHandler中:

代码语言:javascript
复制
student = students.Find( cmd.StudentId );

course = courses.Find( cmd.CourseId );

registration = course.OpenRegistration( cmd.SpecialOffers );

student.Book( registration );

students.Save( student );

这里的关键是上面的内容是声明性的。没有“询问”数据,所以很容易看到正在发生的事情。

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

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

复制
相关文章

相似问题

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