与患者、牙医、治疗和病史的实体和聚合根混淆
Confusion with entities and aggregate roots for patients, dentists, treatments and medical history
我是 DDD 的新手,并决定用我正在开发的牙科诊所系统来练习它,但我正在为域建模而苦苦挣扎,因此非常感谢多一双眼睛。
对于这个牙科系统,领域专家告诉我,一个病人只有一份病史。病史必须有一个在系统上唯一的记录号。病史包含患者可能进行的牙科治疗(如计划治疗)以及患者已经进行的治疗。每种治疗都有价格,因此病史包含总价(基于 planned/applied 治疗)。每当患者完成治疗时,he/she 将不得不支付至少 50% 的治疗费用,这意味着 he/she 最终将在未来的预约中支付剩余的费用(如果没有治疗计划, he/she 将必须支付 100% 的价格)。最后,这家牙科诊所为患者提供了使用不同货币支付的选项,因为有时当天来的患者只有欧元,但随后他决定他想要一个计划,并且未来的预约将支付英镑。
基于所有这些以及我对 DDD 的初学者知识,我的第一个想法是我有这些实体:
- 患者
- 治疗
- 牙医
我会有几个值对象,但最重要的可能是:
- 钱(价格和货币)
- 签名(适用于应用治疗)
- 牙齿或牙齿(用于治疗实体)
而且我只能找到一个汇总,即病史,因为它将患者信息以及治疗(计划和应用)放在一起。但这将意味着每当我更新病史时,我将不得不更新患者信息和治疗,即使其中一个从未改变过。患者可以更改个人信息,这将反映在病历中,但不影响治疗。
我对如何建模有点困惑。请帮忙!
实体有一个 Id,而值对象有结构标识,这意味着如果两个值对象具有相同的值,那么它们就是相同的。
在Money的情况下,两张5美元的钞票之间没有区别,所以它可以是一个值对象。
你没有描述牙齿和签名的作用和属性。
如果是 Tooth,是谁的 Tooth 重要吗?你能用具有相同属性的任何其他牙齿替换患者的牙齿吗?如果确实重要,那么 Tooth 需要一个 Id,因此它是一个实体。
如果是签名,您将如何比较两个签名?您是否有可以比较两个签名的外观并确定它们相同的图像识别软件?您可能有两个签名看起来很相似的患者,他们的签名应该被视为相同吗?
如果您选择 Medical history 作为一个聚合体,那么您应该将其视为一个对象。您是否要加载整个病史,以便为其添加新的治疗方法?治疗可以与另一个实体相关联,例如牙医吗?如果您可以单独使用一部分病史(例如治疗),那么它就不是一个总和。
一些不错的教程:
- Entity vs Value Object 弗拉基米尔·霍里科夫
- Entities, Value Objects, Aggregates and Roots 作者:吉米博加德
请记住,聚合以及扩展的限界上下文 (BC) 是一组属于一起的数据和业务逻辑(以及很可能需要事务性更改的事物)。聚合包含的数据存在是因为业务逻辑需要它,而不是因为某些应用程序屏幕需要它。这对于消除一些混淆并使您摆脱一些限制以设计聚合非常重要。
比如,当你向用户显示病史时,你可能想显示患者的姓名、地址、年龄等,还有治疗价格,但你仔细想想,你不会不需要任何这些来管理病史。根据您的说法,病史有一个记录号、一个 PatientId 和一个 TreatmentIds 列表,可能还有完成日期。
当你想向用户显示病历时,你可以使用UI组合。所以,你得到了病史(主要是一堆 ID 和日期)。然后从 Medical History 的 PatientId 中,你可以从拥有它的 BC 中获取 Patients 的信息。从 TreatmentIds 中,您可以从拥有该治疗的某些 BC 获得治疗描述,并从它们所属的 BC 获得治疗描述。
因此,基于此,您可以构建聚合,而不是基于您域中的 "relevant names",例如患者、治疗或牙医,而是根据它们实现的业务逻辑。
这只是胡乱猜测,但我能想到:
BC Marketing(找不到更好的名字):包含所有治疗的描述、牙医的信息、房间和材料的信息等。因此,文本、图片和其他详细信息。
BC Finances:包括每项治疗的价格、每笔付款的支付记录、每位患者的贷方和借方等信息。负责跟踪所有这些事情。例如,它可以知道什么时候治疗 starts/ends 并根据患者的记录需要支付 50% 或 100% 的费用。这里不需要和病历有直接关系,只需要知道是不是第一次治疗就可以了。
BC Scheduling:负责安排新的治疗并跟踪它们何时开始和结束。这可能包含历史记录,或者如果需要,它可能位于其他地方。
BC Medical:负责保存所有的医疗记录,过敏,牙齿状况等医疗细节
BC Patients Care:负责跟踪患者信息、姓名、国籍、联系方式等
一旦了解了限界上下文,就可以定义聚合。每个 BC 可以有一个或多个。此外,有些事情可能不是一个聚合。例如,病史可能不需要实际的汇总,如果它基本上是治疗 ID 及其制作日期的记录并且没有相关的业务逻辑(病史不会拒绝治疗,对何时应该治疗有意见发生等等,这只是历史)。
不要将此作为推荐设计,而只是想出自己的解决方案的思考过程。
我是 DDD 的新手,并决定用我正在开发的牙科诊所系统来练习它,但我正在为域建模而苦苦挣扎,因此非常感谢多一双眼睛。 对于这个牙科系统,领域专家告诉我,一个病人只有一份病史。病史必须有一个在系统上唯一的记录号。病史包含患者可能进行的牙科治疗(如计划治疗)以及患者已经进行的治疗。每种治疗都有价格,因此病史包含总价(基于 planned/applied 治疗)。每当患者完成治疗时,he/she 将不得不支付至少 50% 的治疗费用,这意味着 he/she 最终将在未来的预约中支付剩余的费用(如果没有治疗计划, he/she 将必须支付 100% 的价格)。最后,这家牙科诊所为患者提供了使用不同货币支付的选项,因为有时当天来的患者只有欧元,但随后他决定他想要一个计划,并且未来的预约将支付英镑。
基于所有这些以及我对 DDD 的初学者知识,我的第一个想法是我有这些实体:
- 患者
- 治疗
- 牙医
我会有几个值对象,但最重要的可能是:
- 钱(价格和货币)
- 签名(适用于应用治疗)
- 牙齿或牙齿(用于治疗实体)
而且我只能找到一个汇总,即病史,因为它将患者信息以及治疗(计划和应用)放在一起。但这将意味着每当我更新病史时,我将不得不更新患者信息和治疗,即使其中一个从未改变过。患者可以更改个人信息,这将反映在病历中,但不影响治疗。
我对如何建模有点困惑。请帮忙!
实体有一个 Id,而值对象有结构标识,这意味着如果两个值对象具有相同的值,那么它们就是相同的。
在Money的情况下,两张5美元的钞票之间没有区别,所以它可以是一个值对象。
你没有描述牙齿和签名的作用和属性。
如果是 Tooth,是谁的 Tooth 重要吗?你能用具有相同属性的任何其他牙齿替换患者的牙齿吗?如果确实重要,那么 Tooth 需要一个 Id,因此它是一个实体。
如果是签名,您将如何比较两个签名?您是否有可以比较两个签名的外观并确定它们相同的图像识别软件?您可能有两个签名看起来很相似的患者,他们的签名应该被视为相同吗?
如果您选择 Medical history 作为一个聚合体,那么您应该将其视为一个对象。您是否要加载整个病史,以便为其添加新的治疗方法?治疗可以与另一个实体相关联,例如牙医吗?如果您可以单独使用一部分病史(例如治疗),那么它就不是一个总和。
一些不错的教程:
- Entity vs Value Object 弗拉基米尔·霍里科夫
- Entities, Value Objects, Aggregates and Roots 作者:吉米博加德
请记住,聚合以及扩展的限界上下文 (BC) 是一组属于一起的数据和业务逻辑(以及很可能需要事务性更改的事物)。聚合包含的数据存在是因为业务逻辑需要它,而不是因为某些应用程序屏幕需要它。这对于消除一些混淆并使您摆脱一些限制以设计聚合非常重要。
比如,当你向用户显示病史时,你可能想显示患者的姓名、地址、年龄等,还有治疗价格,但你仔细想想,你不会不需要任何这些来管理病史。根据您的说法,病史有一个记录号、一个 PatientId 和一个 TreatmentIds 列表,可能还有完成日期。
当你想向用户显示病历时,你可以使用UI组合。所以,你得到了病史(主要是一堆 ID 和日期)。然后从 Medical History 的 PatientId 中,你可以从拥有它的 BC 中获取 Patients 的信息。从 TreatmentIds 中,您可以从拥有该治疗的某些 BC 获得治疗描述,并从它们所属的 BC 获得治疗描述。
因此,基于此,您可以构建聚合,而不是基于您域中的 "relevant names",例如患者、治疗或牙医,而是根据它们实现的业务逻辑。
这只是胡乱猜测,但我能想到:
BC Marketing(找不到更好的名字):包含所有治疗的描述、牙医的信息、房间和材料的信息等。因此,文本、图片和其他详细信息。
BC Finances:包括每项治疗的价格、每笔付款的支付记录、每位患者的贷方和借方等信息。负责跟踪所有这些事情。例如,它可以知道什么时候治疗 starts/ends 并根据患者的记录需要支付 50% 或 100% 的费用。这里不需要和病历有直接关系,只需要知道是不是第一次治疗就可以了。
BC Scheduling:负责安排新的治疗并跟踪它们何时开始和结束。这可能包含历史记录,或者如果需要,它可能位于其他地方。
BC Medical:负责保存所有的医疗记录,过敏,牙齿状况等医疗细节
BC Patients Care:负责跟踪患者信息、姓名、国籍、联系方式等
一旦了解了限界上下文,就可以定义聚合。每个 BC 可以有一个或多个。此外,有些事情可能不是一个聚合。例如,病史可能不需要实际的汇总,如果它基本上是治疗 ID 及其制作日期的记录并且没有相关的业务逻辑(病史不会拒绝治疗,对何时应该治疗有意见发生等等,这只是历史)。
不要将此作为推荐设计,而只是想出自己的解决方案的思考过程。