Domain Driven Design
Domain Driven Design
参考文献:JD云方案
贫血/失血模型
充血模型
由于过去ER模型以及主流ORM框架的发展,让很多开发者对实体的概念还停留在与关系形数据库映射这个层面。从而导致实体只有空洞的属性,而实体的业务逻辑散落各个service、util、helper、handler等各种角落中。这种现象就被称为贫血模型现象。
如何判断自己的工程是否有贫血模型现象?
1、大量的XxxDO或者Xxx:实体对象只包含与数据库表映射的属性,没有行为或者及其少量的行为;
2、业务逻辑在各种service、controller、util、helper、handler中:实体的业务逻辑散落在不同层级、不同类、不同方法中,相似场景有大量的重复代码。
3.4 为什么贫血模型不好?
无法保证实体对象的完整性和一致性:贫血模型下,实体属性的状态和值只能由调用方保证,但是属性的get和set是公开的,因此所有调用方都可以调用。所以无法保证对象的完整性和一致性。
操作实体对象的边界很难发现:由于对象只有属性,属性的边界值、调用范围不受实体自身控制,各个地方都可以调用,边界值和范围也只能由调用方自行保障。如果实体的边界值有所变化,那么所有调用方都需要调整,这种情况下很容易导致bug的产生。
强依赖底层:贫血模型下的实体和数据库模型映射、协议等。因此如果底层改变,那么上层逻辑需要全部跟着改变。“软件”变成了“固件”。
总结一句话:贫血模型下,软件的可维护性、可扩展性、可测试性极差!
使用repository之后,数据模型和领域模型都各司其职。通过Assembler和Converter进行模型之间的转换。
在代码中,动态转换映射 VS 静态转换映射
虽然Assembler/Converter是非常好用的对象,但是当业务复杂时,手写Assembler/Converter是一件耗时且容易出bug的事情,所以业界会有多种Bean Mapping的解决方案,从本质上分为动态和静态映射。
动态映射方案包括比较原始的 BeanUtils.copyProperties、能通过xml配置的Dozer等,其核心是在运行时根据反射动态赋值。动态方案的缺陷在于大量的反射调用,性能比较差,内存占用多,不适合特别高并发的应用场景。而BeanUtils等copy类工具隐藏了内部copy的过程,很容易引发bug且不易排查。
MapStruct通过注解,在编译时静态生成映射代码,其最终编译出来的代码和手写的代码在性能上完全一致,且有强大的注解等能力。会节省大量的成本。
根本原因就是,大部分的开发人员混淆了数据模型和领域模型这两个概念。
数据模型(Data Model):数据模型解决的是数据如何持久化、如何传输的问题;
领域模型(Domin Model):领域指的是某一个独立的业务领域或者问题空间,领域模型就是解决这个业务领域或者问题空间而设计的模型;解决的是业务领域的问题。
在DDD中,repository就是用于区分数据模型和领域模型提出来的概念。