手把手教你落地 DDD
钟敬
Thoughtworks 首席咨询师、数字化转型与运营团队 DDD 负责人
19697 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 45 讲
AIGC特别策划 (2讲)
结束语&结课测试 (2讲)
手把手教你落地 DDD
15
15
1.0x
00:00/00:00
登录|注册

26|泛化的实现(下):怎样为泛化编写代码?

你好,我是钟敬。
上节课,我们学习了泛化的数据库设计,这节课我们接着看看怎样为泛化编写代码。
泛化在程序里,体现为一套有继承关系的对象,而在数据库里体现为若干张表。所以,泛化的编码主要解决的问题就是,怎么把内存中的对象和数据库表里的数据进行相互转换。这个问题解决了,其他部分就和常规的面向对象编程没有什么区别了。
同一个泛化结构,在内存中的对象布局是一样的,但根据不同的数据库设计策略,数据库里的表结构却是不一样的,上节课我们讲过主要有三种。这就造成了泛化关系的持久化问题,比关联关系的持久化要更加复杂一些。
你应该已经想到了,这里说的内存和数据库数据的相互转换问题,是在仓库(repository)里解决的。或者说,仓库屏蔽了不同的表结构的差别,我会结合工时项和客户的例子带你体会这一点。

为领域模型编码

我们首先为工时项以及它的子类编写领域层代码。之前说过,我们要养成边看领域模型,边写代码的习惯,所以先回顾一下领域模型。
本来,传统上的泛化既可以用继承来实现,也可以用不同的属性值来实现。不过根据 DDD 的思路,我们在领域建模的时候,已经有意识地考虑了领域模型和程序实现一致性,所以,对于上图里的泛化,我们直接用继承来实现就可以了。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了在程序中实现泛化和编写查询工时项功能的技术方法。通过具体的代码示例,介绍了领域模型的编码、返回值类型的设计和应用服务的代码编写。文章首先讲解了如何通过实现接口和继承类来实现泛化体系,然后详细介绍了查询工时项的功能,包括对数据库进行多次查询,构造员工可用的工时项列表。随后,文章提出了改进空间,并通过抽取公共方法和利用泛型技巧来解决问题。最后,通过“内联”重构手法,进一步简化了代码。总的来说,本文通过实例展示了如何利用泛化和技术手法来提高代码的可维护性和性能。 此外,文章还介绍了在“每个类一个表”编码策略下的数据库设计,以及如何实现企业客户和个人客户的表结构。通过父类和子类的表关联,以及在程序中的实现方式,展示了如何在泛化体系中实现数据持久化和查询功能。此外,还详细讲解了DAO的设计和使用,以及在数据库操作中的乐观锁实现。通过具体的代码示例,读者可以深入了解如何在实际项目中应用这些技术。 总的来说,本文内容丰富,通过具体的代码示例和技术讲解,为读者提供了深入理解泛化体系和数据库设计的实践经验。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《手把手教你落地 DDD》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(11)

  • 最新
  • 精选
  • 子衿
    1. 公共字段比较多,那么首先从上节课表设计的角度,就不应该每个子类一个表了,先将表的设计改成每个类一个表,此时由于子项目仍然不能是聚合根,因此依然不能使用继承的方式,由于EffortItem中新增了属性值,又不适合作为接口,所以此时考虑将整个EffortItem作为一个属性放入到项目、子项目、普通工时项中,也就是组合替代继承,最终仍然通过Respository消除这种不匹配 2. 可以考虑为CorporateClient创建Builder

    作者回复: 嗯,两个问题的思路都不错。尤其是第1题的组合思路。

    2023-02-09归属地:上海
    10
  • 许勇
    问题1,继承工时项,实现聚合根接口

    作者回复: 是的,用接口继承代替实现继承。

    2023-05-01归属地:北京
    1
  • “此外,Client 是聚合根的子类,这就意味着它的所有子类也是聚合根。” 老师,一个聚合不是只能有一个聚合根吗?这样的话,个人客户也是聚合根,企业客户也是聚合根,那不是冲突了吗?

    作者回复: 注意一点:聚合是对象实例和实例之间的关系,不是类和类之间的关系。从类的角度有三个类:客户、个人客户、企业客户,但具体到对象,比如某个个人客户,就只有一个对象了。关键要理解这句话“聚合是对象实例和实例之间的关系,不是类和类之间的关系”

    2023-04-09归属地:广东
    1
  • tt
    1、按照这里的场景,因为考虑到聚合根和工时项两大特性,只能把工时项作为接口,如果共用字段比较多,那可以写一个默认实现,真正的子类在派生自它,只重写必要的方法。 2、使用builder模式。

    作者回复: 嗯,是一种办法

    2023-02-18归属地:北京
    1
  • 雷欧
    代码在分支上没有啊

    作者回复: 没有什么?

    2024-02-21归属地:浙江
  • + 糠
    多个聚合根对应多个仓库,那应用层是怎么调用的?代码更新了吗?

    作者回复: 在代码的分支上

    2023-11-02归属地:广东
  • Geek_ca43a3
    "如果让 SubProject 也继承 EffortItem 类的话,SubProject 就成了聚合根",这句话怎么理解?

    作者回复: 如果EffortItem是AggregateRoot的子类,而SubProject又是EffortItem的子类,那么,SubProject也就是AggregateRoot的间接子类了,这是,可以说SubProject是一个AggregateRoot。

    2023-06-30归属地:广东
  • 赵晏龙
    1 abstract 2 builder,另外,我一般只在构造函数中放【键】,其他不放。

    作者回复: 1 关键是 abstract 也不能解决 Java 只能单继承的问题 2 没问题

    2023-02-24归属地:湖南
  • 6点无痛早起学习的和尚
    在代码里的 addCorporateClient、updateCorporateClient 方法应该加事务控制吧,看文中没有加

    作者回复: 建议把事务控制加在应用层,而不是Repository上面

    2023-02-21归属地:北京
    2
  • 子衿
    老师这边有个问题想问一下,就是下层肯定是不应该调用上层,那么同层之间可不可以互相调用呢,看示例中,Handler和Repository都是领域层,他们间就进行了互相调用,但如果不同的两个模块的应用服务间,是不是可以互相调用呢,互相调用时,是不是就可能产生循环依赖,这种问题一般怎么解决,也是通过在领域服务层加接口,然后在适配器层实现,从而解决吗,还是有什么最佳实践

    作者回复: 理论上可以互相调用。 尽量避免循环依赖。解决方式有多种,要看具体情况。抽接口也是一种常见的做法。

    2023-02-09归属地:上海
    2
收起评论
显示
设置
留言
11
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部