DDD(领域驱动设计),你必须知道的贫血模型和充血模型
时间:2022-07-28
本文章向大家介绍DDD(领域驱动设计),你必须知道的贫血模型和充血模型,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
背景
- 最近公司开始推行DDD(领域驱动设计),基于充血模型的面向对象开发模式是DDD的特点之一,而在平时开发中我们都使用的是MVC 架构是基于贫血模型的面向过程开发风格,也许有同学就会问了,贫血模型和充血模型是的什么呢?
贫血模型和充血模型
简介
贫血模型:
- 定义对象的简单的属性值,没有业务逻辑上的方法(个人理解)没有找到官方解释
充血模型
- 充血模型也就是我们在定义属性的同时也会定义方法,我们的属性是可以通过某些方式直接得到属性值,那我们也就可以在对象中嵌入方法直接创建出一个具有属性值的对象。也就是说这个对象不再需要我们在进行进一步的操作,这也就复合了OOP的三大特性之一的封装(个人理解)
关于DDD和充血模型的关系
我们在平时进行web开发的时候,就是定义DTO,定义数据库Model,BO等,对其进行get set方法,然后通过service 对Bo对象进行操作,最后通过copy属性持久化数据库和DTO传输。但是如果是充血模型的话,就不用在service进行属性赋值,而是在创建这个对象的时候,进行业务操作,赋予其属性值。这里也就是DDD的思想,这个对象也就是DDD所定义的Entity 或者 value 。Service也就是domianService,由多个Entity 和value 组成,构造最终的领域模型。
下图是作者本人对DDD的理解画的图,也希望能帮到大家理解:
回归正题还是看充血模型和贫血模型 说了这么多DDD思想中的充血模型到底优势在哪里呢?适用于哪些场景呢?而我们都在用贫血模型,但是我们在平时的开发中也没有什么问题呀?
为什么大家都在使用贫血模型?
- 使用贫血模型的传统开发模式,将数据与业务逻辑彻底分离,通过get set方法改变对象属性,对象属性可以随意被修改,这也就如上面所说违反了OOP的三大特性之封装特性。这样的编程方式也就是面向过程的编程方式,面向过程的编程方式是符合人类大脑逻辑的,不用使用太多的设计模式和过多的设计。还有就是在开发中大家经常说的一句及其不负责任的一句话:“怎么方便怎么来”,就一直在堆代码,完全不像以后的可拓展性。也就是说基于贫血模型的编程方式是面向过程编程,人类的思考逻辑方式很符合,在编程过程️也很方便,所以大家都很愿意接受这种编程方式。
- 综上所述:
- 充血模型的设计要比贫血模型更加有难度
- 大家一致使用基于贫血模型的面向过程编程已经成为习惯,比较难转换思想
- 还有就是对代码不负责任的态度。(这是大数程序员的通病吧)
是所有的场景都适合使用充血模型吗?
- 使用充血模型也就是使用基于充血模型的DDD的开发模式,上文也一再强调,充血模型也是定义模式复杂,设计难等,代码开发量也许时其他模型的多,其主要原因还是设计起来难。那就是说如果我们设计一个很简单的业务逻辑,那我们还需要这么复杂的设计思想吗? 并且这个业务在后续的迭代也不变复杂,那我个人认为我们就使用我们的基于贫血模型的面向过程的编程思想。简单的东西何必复杂化呢。这里突然想到我同时讲的一个段子:
- 普通程序员写hello word 直接print
- 高级程序员写hello word 各种设计模式各种可拓展最后输出hello word
- 技术专家写hello word ,直接打印hello word
- 当然我们在进行一个复杂的业务场景,那就需要进行基于充血模型的DDD(领域驱动模型)开发模式了。其实DDD的开发模式也就是充分的遵循OOP发三大特性(或者四大特性,封装,继承,多态,(抽象)),如果是贫血模型的面向过程编程那到最后的结果就是点练成线,由线变成网,密密麻麻不可维护。所以说复杂业务逻辑基于充血模型的进行开发。但是也会是有问题的那就是类膨胀,一个类有很多代码。这个还是可以解决的,那就是通过设计模式,喝业务逻辑细分进行解决。
总结
- 贫血模型和充血模型的简单解释
- 以及DDD开发模式和面向过程编程与充血和贫血模型的关系
- 对比了基于贫血模型的MVC层的面向过程编程范式和基于充血模型的面向对象编程范式的对比
- 两种模型分别适用于那种场景
参考
- https://time.geekbang.org/column/article/169600 设计模式之美
- https://zh.wikipedia.org/wiki/%E5%8F%8D%E9%9D%A2%E6%A8%A1%E5%BC%8F 反面模式
- http://www.cnblogs.com/netfocus/archive/2011/10/10/2204949.html DDD的基础理论喝
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 使用GANs生成时间序列数据:DoppelGANger论文详解
- CentOS 7使用samba共享文件夹的完整步骤
- Linux环境使用crontab命令设置定时周期性执行任务【含php执行代码】
- linux系统报xfs_vm_releasepage警告问题的处理方法
- linux系统报tcp_mark_head_lost错误的处理方法
- Pandas的列表值处理技巧,避免过多循环加快处理速度
- 详解Linux iptables常用防火墙规则
- Linux文件权限与群组修改命令详解
- Spring-IOC-从单例缓存中获取单例 Bean
- Linux上为你的任务创建一个自定义的系统托盘指示器
- 14个Seaborn数据可视化图
- Linux中的进程守护supervisor安装配置及使用
- 《JavaScript数据结构与算法》读书笔记
- 《JavaScript函数式编程指南》读书笔记
- 冒泡排序