ddd 在业务域的落地- 无领域术语下如何给领域实体的命名 hibernate区别 ,中台

如何理解领域设计中的分层,服务编码,各业务对领域的不同处理.

强烈推荐的文章,详解DDD系列(

殷浩详解DDD系列 第一讲 - Domain Primitive

殷浩详解DDD系列 第二讲 - 应用架构

殷浩详解DDD系列 第三讲 - Repository模式

)

自己的更好的文章: DDD 是啥,cqrs是啥

领域设计=  领域模型(hibernate擅长,但又太重,见repository)

                      + 领域实体 (充血模型)

                      + repository ( hibernate的关联list,屏蔽了repository概念, 让程序员很容易再内存中过滤,导致性能问题. 为什么不用hibernate的原因.  另外hibernate不能解决外键是hsf的问题,分布式.)

                     + 事件流 (即现在的分布式弱依赖模式)

                     + 内存中插件流(一个流程涉及到不同的领域类+ 流程上下文 ,before  after 接口,见附件图. )

                     + 分布式插件式( 一个流程中一个领域类被不同的业务处理, bz上下文+当前crd的DO, 业务校验, 即中台 ,中台需要 levelDb+线上列式存储,才能充分体现价值, 状态无非表现了n种属性值, 方便后续查询. crud . 中台要有能力自动生成接口, 而不是文档式hashmap, 避免内部逻辑重构导致中台插件失败, 如何解耦代码是个问题,要专门搞一层内部context和外部context的转换逻辑,注解.)

代码可维护性-

    "权限隔离" 不如 "领域字段隔离" , 一个个充血模型天然就隔离了. 你的处理某领域的代码再也不会放到另外一个领域的manager下去了.

原则:

  1.自己的EO不引用别人. 每个字段只能存在于一个EO中,避免封装混乱.

2.组合大于继承 (更灵活,更容易中台化,拆分到其他系统)

   使用责任链工具manager 如下图1

   因为原则1,如果其他EO的逻辑要用到其他EO中的字段,必须通过形参传入. 理论上只能单向依赖. 另外必须通过EO传递. 如果只有id时,通过manger 从dao中获取并组装.

3. 再次强调 别人的EO不能持有其他的EO,或者其他EO的字段. 也不能通过方法直接从dao里获取数据. 也就是不能有

ApplicationContextUtils类.

 原因: 如果是非同jvm内,方法形参通过id传播. 同jvm内,最好通过EO传播,这样的话,可以少生成Eo,减少垃圾回收.  

4. 这样做以后, 复杂查询的manager会复杂点. 其他业务manger就很薄了.下沉到领域实体中(EO). 

5. 返回的bean和领域实体11对应,多了一些外键id. 这些属性根据不同的外露接口可以赋值,也可以不赋值? 最好单独写新的bean. 

通过mapstruct 按需去赋值,字节码.  这样调用方不会被误导.

   

见qq邮件,如果图片不见后

图1:

图2

    遗留两个问题

        1. 但充血模型还是有个问题, 外部可以拿到这个领域类,获取其属性,再领域外进行逻辑处理,代码又乱了. 这个是正常的,因为user系统重要透出自己的属性给外部,外部根据user的属性去封装逻辑. 不可能都下沉到user类里来. 所以这时候会有新的领域类出现. 给user加个前缀,或者新赋予一个领域术语. 例如 人 变成了 父亲 . 有可能用继承,也有可能用组合. 建议继承. 

    Param再转成Entity,再转换成DO很关键

      2. 同一个系统下,业务很多, 同一些字段属性处理, 都往user领域里加方法. 越来越多,这个时候就需要进行梳理了,将业务进行分离. 最方便的方法就是加个业务前缀,当然通过同名但通过不同的包也行.但是对后续代码可书写性会较差.

     3. 组合还是继承? 继承是中台玩法,插件回调,中台含有扩展存储,流程组装暴露接口只有一个. 各个继承类实现自己的回调即可.
        组合呢,中台提供基础能力,没有流程组装. 组合层层封装. 一开始先继承简单快速,少整理接口类, 继承爆炸后改成组合就要把原来的方法抽取出接口. 这样才能保证原有的代码改动最小. 改成组合后,原来的abstract 变成了接口实现了的一个调用.

  * 领域实体不能操作数据库等存储层或者hsf层,需要service来组装.

  * 领域实体和表(存储的区别)是 领域实体可以继承,存储可以泛化存储,以json,文档型等都可.

  * 通过现有代码无法自动化进行架构切割, 通过新增依赖来进行模块划分是一种比较好的方法,增加内聚和依赖的认知成本,确保一个模块的依赖模块最简化. 所以开放需要单独成一个模块,因为要了解开放系统. 根据流程+实体来切割. 滴滴企业打车为啥是专门的系统就是因为增加了企业实体.需要需要专门的部门和系统来支持. 这种划分有助于生产力.

   3. 如何和spring单例 dao结合, hsf facade ? 

        通过spring的ContextAware来实现静态获取. 会有个容器关闭的问题. 所以close容器之前必须先断流.

   4. 接口和继承的关系? 

         流程金字塔,逻辑流程编排通过接口(接口无形参,把参数转成领域属性,不同领域类参数会变. 领域类本质就是封装属性字段).  领域实体必须实现接口, 如果实体之间继承,那么新增领域实体会简单些,但是会存在重载的问题(类似广告里每个广告类型计费方法不同,重载,解决方案是 引入计费接口. 不同的广告类依赖不同的计费接口. )

  5. 责任链(before,after切面)的引入进行流程插件化改造,核心不变,新的业务,通过旁路系统或者插件系统引入. 流程编排,通过端上来编排. 每个能力提供扩展点. 类似星环. 

一个领域如果有术语就比较简单.

例如: 轮子和框架组合在一起的组装类可以取名为汽车, 还可以继承后变成了小汽车,suv.

这样整个实体的依赖,继承体系就建立了. 轮子可以继承为很多子类,汽车也可以继承为很多子类. suv汽车的很多功能可能是根据各个轮子/轴承的继承组件组合在一起的.使用的功能已经不再是普通轴承的功能(方法)了.

例如会议室预订的领域实体命名.

一个实体如果领域里不能给出具体的术语,就只能自己根据属性来定义名字

例如 

 会议室预订下面有 会议室和预订列表.

本来纠结了半天 两个都叫 预订,怎么区分?

一种方法是把上面的预订 加个 "组装"词汇. 叫做RoomBookAssembleVo;

另外一个方法是预订item,可以加上重要的时间信息.

Roombook {

Room;

List<BookTimeVo> 

}

猜你喜欢

转载自blog.csdn.net/fei33423/article/details/106564474