当前位置: 首页 > news >正文

初识DDD架构

一、前言

        之前实习的时候,从Java转向Go语言,接触到了DDD架构(实习公司的项目是DDD架构),不过那个时候没有对DDD架构有系统的认知和学习,现在秋招结束,新公司主要使用的就是Go语言,因此打算进一步对DDD架构学习,自己通过一个实例接口,对DDD架构记录自己的独特理解

二、什么是DDD

1.架构分层

2.各层数据

  • VO(View Object):视图对象,简单来说就是针对具体的场景,返回指定的数据给前端

  • DTO(Data Transfer Object):数据传输对象,主要用于远程调用等需要大量传输对象的地方。过去大部分场景,接收前端参数,或者说返回给前端参数,或者说跨服务传输数据,用DTO更多一点,对于某个DTO,其中某些属性不想或者不能返回的时候,就需要把DTO转换成VO了

  • DO(Domain Object)/ MO(Module Object):领域对象,就是从现实世界中抽象出来的有形或无形的业务实体。这个说法太抽象了,简单来说,这是一个游离在领域层的一个业务载体 这样说还是有些抽象,我们把他的作用分为两个

    • 1.存储领域数据:举个例子,一个user对象,有很多属性,比如username,password这两个属性,来自于user_login这张表,还有其他属性,例如realname,age,来自于user_info这张表,不同的表有不同的PO,不同的PO有各自的属性,而这些属性都对应着同一个user,此时这些来自不同表中的属性,都可以存储到MO当中,方便领域层的操作

    • 2.封装业务逻辑:Service层固然会处理领域层的各种业务逻辑,但是主要是用来处理,多个MO之间交互的业务逻辑,单个MO之内的业务逻辑,可以封装到MO当中,这就是所谓的充血模型

  • PO(Persistent Object):持久化对象,它跟持久层(通常是关系型数据库)的数据结构形成一一对应的映射关系,如果持久层是关系型数据库,那么,数据表中的每个字段(或若干个)就对应 PO 的一个(或若干个)属性。

三、DDD和MVC的比较(为什么用DDD)

DDD其实由我个人的使用和理解来看,是在分布式项目崛起之后,对MVC进行了专项的升级

或者说,MVC本身架构是存在一些问题的,DDD进行了优化,并且这个优化很符合分布式项目的特点

首先,一句话总结,DDD的核心区别,是把MVC的Service分化成了应用层和领域层

看似很小的改动,但是带来的巨大变化是:把MVC的按功能分层,转换成按业务分类

1.MVC的问题

过去因为基本上都接触的Java代码,MVC接触的较多,一个很明显的特点就是,不管什么接口和实现,加个注解,就会被Spring自动装配,然后加个@Autowired就可以直接用。这样带来的好处是,我们可以很方便的在任一层里,调用任意接口,依赖注入就完事了

但是这样就会存在一个问题

假如我们现在要做一个电商订单下单的需求,涉及到用户选定商品,下订单、支付订单、对用户下单时的订单发货

MVC 架构:我们常见的做法是在分析好业务需求之后,就开始设计表结构了,订单表,支付表,商品表等等。然后编写业务逻辑。这是第一个版本的需求,功能迭代饿了,订单支付后我可以取消,下单的商品我们退换货,是不是又需要进行加表,紧跟着对于的实现逻辑也进行修改。功能不断迭代,代码就不断的层层往上叠。最简单的实例就是,一个中小MVC项目,你可以看到service这个目录下,有几十上百个service接口和实现类

根本原因就是因为,我们把service这一层存放了所有的业务逻辑,只要加新功能,我们的想法就是,加个新的service接口和impl实现,然后在这个service里面,去编写业务逻辑

2.DDD的出现

在我的理解来看,DDD很早其实就出现了,真正的投入广泛使用,应该是分布式系统的出现。比如据我了解,目前阿里、PDD等使用Java开发较多的公司的项目,采用的还是传统MVC架构,因为Spring的IOC确实太方便了,但是例如字节、bilibili这种新型公司,开始广泛使用Go语言+分布式系统之后,DDD的架构就非常适合分布式的这种理念

简单来说,就是对整个项目划分业务边界,在分布式系统中,一个功能就是一个项目,通过rpc或者说http协议连接起来,相对应的,DDD架构,一个领域就对应一个功能,甚至在强分布式的系统当中,一个DDD项目里面就只有垂直的一个领域

以至于我认为DDD本身的定义在分布式的系统当中,体现的反而没有传统一体化项目明显。举个例子,还是之前的电商下单,我们有三个功能,下单,支付,发货。如果是在一体化的项目当中,我们可以通过领域层的分化,把这三个功能,分为三个领域。但是在分布式系统当中,每个功能可能都单独分成了一个独立的项目,在这个独立的项目当中,可能就只有这一个领域了,DDD本身相对于MVC的优化就没有得到更好的体现

3.总结

MVC这个架构,是按照功能分层的,最大的问题就是,我们一旦需要加新功能,就在service目录当中新开接口和实现类,久而久之service层就会很冗杂,也不好维护

而DDD架构,会根据不同的业务逻辑,按照领域进行分类,这种设计,本身就极其符合分布式系统的理念,因为假如在同一个项目当中,这样分类感知其实不太明显,但是如果把不同领域分布在不同的项目当中,然后通过一些协议,例如rpc进行连接,这样让不同的团队负责不同领域的功能/项目,可以提高开发效率

简单来说,MVC是把所有功能都放到service的大杂烩

而DDD是把整个项目,按照功能分类,每个功能的模块本身也就还类似于一个被分化后功能单一的MVC

四、实例接口感受DDD

这里用Go代码,编写了一个用户登录的场景,直观感受DDD的重要特点

DDD相较于传统MVC,最关键的就是把传统的service分为了应用层和领域层

1.应用层

应用层的主要作用是编排业务流程,简单来说就是,拼装service里的业务逻辑

func (m *UserManagerImpl) UserLogin(requestDTO *dto.UserLoginRequestDTO) (*dto.UserResponseDTO, error) {// 参数校验if requestDTO.UserName == nil {return nil, errors.New("用户名不能为空")}if requestDTO.Password == nil {return nil, errors.New("密码不能为空")}// 查询用户是否存在userLogin, err := m.userService.GetUserLogin(dto.UserRequestDTOToMo(&dto.UserLoginRequestDTO{UserLoginId: requestDTO.UserLoginId,UserName:    requestDTO.UserName,}))if err != nil {return nil, err}// 校验密码if *userLogin.Password != *requestDTO.Password {return nil, errors.New("密码错误")}// 查询用户的额外信息userInfo, err := m.userService.GetUserInfo(&model.UserMO{UserLoginId: userLogin.UserLoginId,})if err != nil {return nil, err}// TODO: 生成token...// token := m.tokenService.GenerateToken(userLogin.UserLoginId)return dto.UserMoToResponseDTO(userInfo), nil}

可以看到,这个用户登录接口的应用层代码,分为了几个部分:参数校验--判断用户存在--校验密码--查询用户信息--生成token

其中,判断用户存在查询用户信息分别调用的是userService接口的方法,他们都同属于user这个领域

生成token调用的是tokenService接口的方法,这个属于tokenService这个领域

也就是说,每一个领域层的service,只负责其这个领域的业务逻辑,DDD添加了一个应用层来对这些不同领域的业务逻辑,进行排列组合,让逻辑变得更清晰,service层的代码可以分类的更好

在分布式的系统当中,调用其他服务的接口,也就算作调用跨项目的业务逻辑,同样是放在应用层当中

2.领域层

而领域层,就是纯粹的封装业务逻辑

传统的MVC,Controller下面就是service,service里面包含了许多逻辑,会经常出现,service中调用其他service,这样串联嵌套的情况,对于故障排除,后续扩展非常不友好

而DDD的领域层,存放的是纯粹的业务逻辑,封装的是多个Repository接口的查库操作

func (s *UserServiceImpl) GetUserLogin(mo *model.UserMO) (*model.UserMO, error) {userMO := model.UserMO{UserLoginId: mo.UserLoginId,UserName:    mo.UserName,Password:    mo.Password,}return s.userRepository.GetUserLogin(&userMO)}​func (s *UserServiceImpl) GetUserInfo(mo *model.UserMO) (*model.UserMO, error) {userMO := model.UserMO{UserLoginId: mo.UserLoginId,}return s.userRepository.GetUserInfo(&userMO)}

五、优化方向

可以看到应用层的代码当中,存在参数校验密码校验的逻辑

可以把这种应用层的逻辑,封装到MO当中,优化成为一个充血模型

http://www.dtcms.com/a/572894.html

相关文章:

  • 一次redis内存泄露故障分析
  • 计算机网络自顶向下方法32——网络层 网络层概述 转发和路由选择,数据平面和控制平面(传统方法,SDN方法) 网络服务模型
  • 深入理解MySQL_3 I/O成本
  • 哪个网站可以做验证码兼职gom传奇网站建设
  • 做网站一年能赚多少钱没有备案的网站怎么挂广告
  • vscode-ssh无法进入docker问题解决
  • iOS 应用网络权限弹窗的问题及解决方案
  • 使用 FastAPI 异步动态读取 Nacos 配置
  • 怀远做网站电话网站建设期末作业要求
  • Arbess零基础学习 - 使用Arbess+GitLab实现PHP项目构建/主机部署
  • CS144 Lab:Lab0
  • 总结做产品开发的一些通病
  • 稳定币市场格局重构:分发权正在成为新的护城河!
  • 【C语言】深入理解指针(二)
  • C++:模板的灵魂——从编译期推导到元编程的演化史
  • 开发网站用得最多的是什么语言电子商务网站开发课程
  • 顺德中小企业网站建设网站销户说明
  • Python3 面向对象编程详解
  • 【 SLF4J + Logback】日志使用方法+技巧介绍+项目示例(SpringBoot)
  • 重构可见性:IT资产管理的下一次觉醒
  • mermaid install for free docker
  • 0 基础学前端:100 天拿 offer 实战课(第 6 天)—— JavaScript 入门:给网页加 “动态交互” 的 3 个核心案例
  • 宝塔nginx http转https代理
  • 建设企业网站登录901如何修改wordpress主题模板
  • 系统架构设计师论文-论软件体系结构的演化
  • 【大模型学习】第一章:自然语言处理(NLP)核心概念
  • 软件测试之压力测试知识总结
  • 高级系统架构师笔记——系统架构设计基础知识(3)软件架构风格
  • 备案网站负责人必须为法人吗网站建设需要客户提供什么内容
  • QML学习笔记(五十一)QML与C++交互:数据转换——基本数据类型