本文介绍了处理聚合根的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是DDD的新手,所以我正在做一些练习,以了解更多内容.我有遵循以下规则的BC课程:

I'm new in DDD so I'm doing some practice to undertand a little bit more. I have Course BC with the follow rules:

  1. 必须先创建课程,然后他们才能创建一个课程的模块
  2. 用户上传作业后,每个模块都会完成
  3. 用户将在完成所有模块后完成课程

定义:一门课程涵盖特定主题,由模块组成.例如,SAP课程有10个模块,例如:模块1:是什么?模块2:如何使用它?…

Definition:A course covers a particular topic and it is comprised of module. For instance, sap course has 10 modules such as: module 1: what is it?, module 2: how to use it?…

此后,我意识到Course是模块的聚合根,因为模块完成了,所以我必须关闭该课程的用户状态.

After this, I realize that Course is the aggregate root of module, because the modules are finished I have to close the status of user with the course.

模型应为:

public class Course : AggregateRoot
{
    private string title;
    private List<Module> modules;
}

而且模块也是家庭作业的总根,因为当用户上传他的家庭作业时,该模块必须关闭.这使我认为这种方法是错误的,因为在DDD中不可能嵌套聚合根.有人知道这是什么问题吗?

but also module is an aggregate root of homework because when the user upload his homework the module has to be closed. This make me think that this approach is wrong because is not possible in DDD have nested aggregate root. Someone knows what is it wrong?

[已更新]

好吧,现在我了解了工作原理以及为什么要在公元前2年将其拆分.但是我做了一些更改,并且想到了一些问题.

Ok, now I understand how is work and why you split it in 2 BC. However I did some changes and some questions come to my mind.

-我已经将enroll方法创建为静态方法,并将构造方法设置为私有.

-I've created enroll method as static and I put the constructor as private.

-课程必须是一个数组,因为一个学生可以拥有多个.

-Course have to be an array because one student can have more than one.

-我输入了与课程以及老师相关的更多参数.当然是老师和实体了吗?

-I've put more parameters related with the course and also the teacher. Is the teacher and entity of course, right?

-我当然创建了状态,以便在模块完成后以这种方式更新它,而不必阅读所有模块即可知道它.可以吗?

-I created status of course to update it when the module is finished this way I don't have to read all the modules to know it. is ok?

-如何为每个模块传递更多信息,例如标题和说明?课程实体是如何创建所有模块的,对吗?

-How can I pass more information for every module like title and description? and is the course entity how create all the modules, right?

public class StudentEnrolment: AggregateRoot
{
    private StudentId studentId;
    private Course courses;

    private constructor(
        StudentId studentId,
        Course course,
       ){
        this.studentId= studentId;
        this.courses[] = course;
    }

    public statuc function enroll(
        StudentId studentId,
        CourseId courseId,
        string courseTitle,
        string courseLink,
        string teacherId,
        string teacherName,
        List<Tuple<ModuleId, string>> modules) {
        teacher = new Teacher(...);
        courseStatus = new courseStatus();
        new course(courseTitle, courseLink, courseStatus, teacher);
        return new self(studentId, course);
    }

    public function void uploadModuleHomework(ModuleId moduleId, Homework homework){
        /* forward to course.uploadModuleHomework */
    }

    public boolean isCourseFinished(){
         /* forward to course.isFinished */
    }

    public List<Tuple<ModuleId, string>> getModules(){
         /* forward to course.getModules */
    }
}

推荐答案

有两个不同的子域(因此我们有两个有界上下文):

There are two different sub-domains (so we have two bounded contexts):

1.课程和模块管理,教师可以在其中进行管理;这里的 Course Module 可以是聚合根,而 course 可以保存对 Modules ID(而不是实例)的引用.!).

1.Courses and modules administration where the teachers can administer those; Here Course and Module can be Aggregate roots and a course could hold references to the Modules IDs (not to instances!).

public class Course: AggregateRoot
{
    private string title;
    private List<ModuleId> modules;
}

2.学生参加课程.这里有一个 StudentEnrolment 聚合根,它包含来自另一个BC的 Course Module 的引用,但作为Value对象;它为学生参与单个课程建模;在这种有限的上下文中,有一个新的实体,即家庭作业,可以跟踪学生的家庭作业上传量和课程参与状态.

2.Student participations to the courses. Here there is a StudentEnrolment Aggregate root that contains references to the Course and Module from the other BC but as Value objects; it models the student participation to a single course; in this bounded context there is a new Entity, Homework, that track the student homework-upload and course participation status.

public class StudentEnrolment: AggregateRoot
{
    private StudentId studentId;
    private Course course;
    private List<Homework> homeworks;

    // initialize a student enrolment as public constructor or make constructor private and use a static method
    // here is important to notice that only this AR creates its entities, it does not receive them as parameter
    public constructor(
        StudentId studentId,
        Course course,
        List<Module> modules){
        this.studentId = studentId;
        this.course = course;
        //build the the homeworks entity list based on the modules parameter
        //for each module create a Homework entity, that initially is not uploaded, like:
        this.homeworks  = modules.map(module => new Homework(module))
     }

    public function void uploadFileForHomework(ModuleId moduleId, string file){
        /* find the homework by module Id and upload file*/
    }

    public boolean isCourseFinished(){
         /*returns true if all homeworks are uploaded*/
         /*optimization: you could have a status that is updated when a homework's file is uploaded*/
    }

    public List<Tuple<ModuleId, string, boolean>> getHomeworks(){
         /* returns a list of readonly Homeworks, i.e. Tuple<ModuleId, string /*module title*/, boolean /*is uploaded*/> */
    }
}


public class Homework: Entity
{
    private Module module;
    private string file;
    public constructor(Module module){
        this.module = module;
    }

    public void upload(string file){ this.file = file;}

    public boolean isUploaded(){return (boolean)this.file;}

    public string getUploadedFile(){return this.file;}

    public ModuleId getModuleId(){return this.module.getId();}
}

public class Course: ValueObject
{
    private string title;
    private CourseId id;
    public constructor(id, title){...}
    public string getTitle(){return this.title;}
    public string getId(){return this.title;}
}

public class Module: ValueObject
{
    private string title;
    private string description;
    private ModuleId id;
    public constructor(id, title, description){...}
    public string getTitle(){return this.title;}
    public string getDescription(){return this.description;}
    public string getId(){return this.title;}
}

如果您需要查询注册以获取家庭作业,则不应返回家庭作业列表,因为客户端代码会认为它可以直接调用 Homework.upload(file),而不是允许(只有聚合根可以修改其内部实体).相反,您可以返回一个Tuple或更好的Tuple,可以创建Homework类的不可变版本.

If you need to query the Enrolment to get the homeworks you should not return a list of Homeworks because the client code would think that it can call Homework.upload(file) directly, which is not permitted (only the Aggregate root can modify its internal entities). Instead, you could return a Tuple or better, you can create an immutable version of the Homework class.

这篇关于处理聚合根的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-12 19:16