首页 > > > 尝试转移一部分行为给值对象
保持实体专注于身份这一职责很重要,因为这样会避免它们变得臃肿————这是它们将许多相关行为拉到一起时容易掉入的陷阱。实现这一专注需要将相关行为委托给值对象和领域服务(领域服务也将在后期的文章中进行介绍)。
来考虑一下最近一版的代码,我们已经将行为划分给了Itinerary了,但是仔细看一看,我们在后期增加需求时增加了一条验证的规则,那么这个规则我们可以转移给值对象吗? 答案是,可以的。而且转移是有必要的,因为对备注的效验这一行为往往应该属于它自身。就好比机器启动时的自我效验,这一行为是属于操作者还是机器自己呢?
所以我们来将部分行为转移给值对象,优化后的代码可能是这样的:
publicclassItinerary{publicintID {get;set; }publicList
愿景是美好的 现实是残酷的
到这里,我们仿佛真的一帆风顺:建立了属于自己的实体,并且融合了该有的值对象,实体的行为也被高度内聚在了其中。那是不是我们直接就可以将DDD落地了呢? 不好意思,就如同这个小标题一样,现实真的是非常残酷的。如果单单从代码阅读和业务处理上来说,我们可能确实已经成功了,但是!!!我们需要保存我们的数据,也就是持久化。因为实体中包含了大量的值对象,所有值对象持久化所面临的问题,它都会遇到,甚至是让难度翻倍!有关值对象持久化的难点可以参考上一篇文章 如何运用DDD - 值对象 。
回看我们最后一版代码,我们有两个集合的属性(Participants、Places)。单一的值对象的持久化已经让我们头痛了,现在我们不得不面对持久化值对象集合的问题。假如你通过使用EF Core这类的ORM框架来进行持久化操作,你会发现我们不得不为List中的值对象加上一个ID,此时拥有了唯一标示的值对象显然已经成为了实体,这是非常可怕的一件事。我们辛辛苦苦建立的领域模型在最后一步落地时居然成为改变了,这往往也是DDD落地困难的一个重要原因,被ORM框架或者关系型数据库所限制,导致领域模型不断被打乱,重构领域模型变得越来越四不像,最终又写回了传统的三层架构或者面向数据库建模。
但是至少在现在,请相信自己的所见,认真考虑和发现你项目领域所拥有的值对象和实体,不要因为知道持久化的问题而放弃和妥协,这也是我们开发者应有的勇气。在后面的文章中,我们会关于值对象和实体的一些问题提出解决办法,当然包括持久化的问题。
总结
本文我们介绍了实体的概念以及怎么去运用实体到实际代码中,请牢记前人为我们提供的有关实体的经验:比如“实体一定是基于领域当前环境(上下文)的”、“实体是高度内聚和自治的”、“应该专注于实体的行为而非数据”等等。后面的文章会为大家带来实体和值对象的一些注意事项以及领域服务的内容。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69949628/viewspace-3165874/ ,如需转载,请注明出处,否则将追究法律责任。