浅谈架构设计:MVC架构与DDD架构【开发实践】

一、架构知识基础

1.1 名词概念

耦合性:指模块之间联系的紧密程度。模块之间联系得越紧密,它们的耦合性越强,模块间的独立性就越差
内聚性:指一个模块内部各个元素之间联系的紧密程度。一个模块内的各元素之间联系得越紧密,该模块的内聚性就越高

1.2 低内聚的坏处

一个模块的内聚性很低,表现为模块的功能不单一,各功能间联系很小,甚至没有联系。这违背了单一职责原则。当类的职责过多时,它们会变得难以维护和理解,因为任何职责的变化都可能影响到其他职责。

1.3 高耦合的坏处

耦合度很高可能导致“牵一发而动全身”,模块的维护和扩展将变得很复杂。因为修改一个模块会牵连到与其关联的模块,这些模块的异常又可能影响与它们关联的模块,进一步导致恶性循环。

1.4 依赖倒置原则

面向对象设计的六大原则之一,其核心思想:

  • 高层模块不因该直接依赖低层模块,而是依赖其抽象
  • 抽象不应该依赖细节
  • 细节应该依赖抽象

术语解释:

  • 依赖指个组件或模块需要调用另一个组件或模块(即依赖的含义等价于使用和调用)
  • 高层模块和低层模块是架构设计中的一种相对概念,允许高层调用低层,不允许低层调用高层
  • 抽象就是指接口或抽象类,细节就是实现类

强化理解:上层中的类A直接依赖于下层的接口B,接口B有多个实现类C和D,如此实现了上层与下层之间的解耦。当我们将接口B的实现类从类C切换到类D,或修改类B的代码时,可以减少或者避免修改上层类A中的代码。

二、MVC架构

2.1 层的划分以及各层的职责

  • Model:模型层,负责处理数据和业务逻辑,包括对数据的存储、读取、验证等操作。模型是应用程序的核心组件,与视图和控制器相互独立,可以被其他应用程序重复使用
  • View:视图层,负责显示用户界面,将数据呈现给用户。视图通常是根据模型中的数据生成的,可以根据需要进行定制和修改
  • Controller:控制层,负责协调和管理模型和视图之间的交互,并处理用户输入和操作。控制器接收用户的请求,更新模型和视图,将结果返回给用户。控制层作为三层的中心,起着“承上启下”的作用,通过调用下层来为上层提供服务,本身不涉及任何业务操作

2.2 请求的处理流程

(配图来源:MVC与三层架构理解
在这里插入图片描述

  1. 用户发送请求,请求由控制器接收并处理
  2. 控制器根据用户请求选择相应的模型和视图,并将请求传递给模型
  3. 模型根据请求处理数据,并将处理结果返回给控制器
  4. 控制器根据模型返回的数据更新视图,并将更新后的视图返回给用户

2.3 MVC架构的优点

分层的目的都是为了实现“高内聚,低耦合”。在MVC架构的三层中,任何一层的变化都不会影响到其他层。

2.4 Spring MVC的三层架构

Spring MVC针对MVC架构进行了进一步的封装,帮助开发者屏蔽底层细节,并且开放出相关接口供开发者调用,让MVC开发变得更加简单。

具体来说,Spring MVC的三层指controller层、service层和dao层。其中controller层负责路由,是Spring MVC中的表现层,相当于MVC架构中View+Controller层。Spring MVC将Model层拆分成了service层和dao层,前者负责业务逻辑,后者负责数据库的操作。

Spring MVC将Model层进一步地拆分成了service层(业务逻辑层)和dao层(数据访问层),其中service层用来实现业务逻辑,而dao层负责数据库操作。(个人理解,可能不对:将view层和controller层合并为新的controller层,作为表现层暴露接口,将model层拆分为service层和dao层)

Spring MVC中的请求处理流程:(配图来源:超详细讲解SpringMVC三层架构
在这里插入图片描述

三、DDD架构(Domain Driven Design)

3.1 经典的DDD架构

(配图来源:DDD架构
在这里插入图片描述

  • 用户接口层(User Interface ):负责向用户显示信息和解释用户指令(是DDD架构中的表现层)(表现层是视图层的超集,概念有所区别,知道最上层就是表现层即可)
  • 应用层(Application):很“薄”的一层,理论上不应该有业务规则或逻辑,主要面向用例和流程相关的操作。在应用层协调多个服务和领域对象完成服务的组合和编排,协作完成业务操作。此外,应用层也是微服务之间交互的通道,它可以调用其它微服务的应用服务,完成微服务之间服务的组合和编排
  • 领域层(Domain):是实现企业核心业务逻辑,通过各种校验手段保证业务的正确性。领域层主要体现领域模型的业务能力,它用来表达业务概念、业务状态和业务规则。领域层包含聚合根、实体、值对象、领域服务等领域模型中的领域对象
  • 基础层(Infrastructure):贯穿所有层,为其它层提供通用的技术和基础服务,包括第三方工具、驱动、消息中间件、网关、文件、缓存以及数据库等

个体理解:将service层拆分为了应用层和领域层。其中应用层关注于用例和流程,不涉及业务规则或逻辑,通过组合和编排下层的领域层来完成业务操作。而领域层用于封装具体的业务规则或逻辑,拆分出来的领域层不再和具体流程关联,实现了高内聚和低耦合,还提高了领域层的可复用性。用户接口层和基础层则为原来的视图层和dao层的扩展,新增了部分职责功能。

3.2 改进的DDD架构(微服务中常用)

以下仅为一个示例,相较于经典的DDD架构新增了facade层和remote层。在实际的开发中,不同公司采用的项目结构可能会有所差异,但是大体结构应该是一致的。

关注点:一级层级的划分,一级层级的调用关系,二级子层的划分,二级层级的职责

3.2.1 层级划分方式和调用关系(依赖关系)

在这里插入图片描述
facade层级的说明:单独抽离出来的一层,专门负责对API层提供入参DTO、出参DTO和错误码

依赖倒置的体现:应用层直接依赖于领域层的接口(如repo和gateway),通过这些接口间接依赖于下层中具体的实现类(基础设施层中的repoImpl和远程服务层中的gatewayImpl)

3.2.2 细分的层级划分及其职责

├─com.company.microservice
│    │ 
│    ├─api   用户接口层 
│    │    ├─config           全局配置     
│    │    ├─controller       控制器
│    │    ├─job              任务调度
│    │    ├─mq               消息接收
│    │    └─StartMain        启动类
│    │ 
│    ├─facade   门面层 
│    │    ├─common           入参DTO和出参DTO的通用超类     
│    │    ├─errorcode        错误码
│    │    ├─request          入参DTO(相当于传统的VO)
│    │    └─response         出参DTO(相当于传统的DTO)
│    │ 
│    ├─application   应用层    
│    │    ├─service          应用层接口服务
│    │    ├─convert          负责DTODO的转换
│    │    └─***              others
│    │ 
│    ├─domain   领域层
│    │    ├─entity           领域对象DO(相当于传统的BO)
│    │    ├─gateway       	 网关接口
│    │    ├─repo       		 dao接口
│    │    ├─enums            枚举
│    │    ├─contents         常量
│    │    └─domainservice    领域层服务
│    │ 
│    ├─infrastructure   基础设施层    
│    │    ├─mapper     	     持久层接口映射
│    │    ├─pojo      		 持久化对象PO
│    │    ├─repoimpl         dao接口实现
│    │    ├─convert          负责DTOPO的转换
│    │    └─resources/sqlmap sql资源配置
│    │ 
│    └─remote   远程服务层
│    │    ├─feign            内部feign接口    
│    │    ├─gatewayimpl      网关接口实现
│    │    └─convert    		 负责DTODO的转换
│    │ 
│    └─test   单元测试层
│    │    └─*** 

数据库操作
接口在domain层的repo,实现在infrastructure层的repoimpl。
使用时在service层中调用repo实现数据库操作。

外部接口调用
接口在domain层的gateway,实现在remote层的gatewayimpl。
使用时在service层中调用dateway来调用外部接口。

补充:service调接口,接口与实现分离的意义

  • 解耦合:通过定义清晰的接口,确保模块之间仅通过接口进行通信,而不直接依赖于彼此的具体实现。这样,当实现细节发生变化时,不会影响到使用该接口的其他模块,从而降低了系统的耦合度,提高了灵活性和可维护性。
  • 复用:将常用代码封装为一个类,在集中管理的同时,还能减少代码冗余。

3.2.3 数据流示意图

在这里插入图片描述

3.2.4 相关POJO的理解

在改进的DDD架构中,涉及三种POJO

  • DTO:表现层与服务层之间的数据传输对象,包括表现层到服务层的数据传输对象requestDTO,和服务层到表现层的数据传输对象responseDTO
  • DO:领域对象,表示业务实体,即封装具体业务方法所需的数据
  • PO:持久化对象,表示数据库中的表与持久层中的实体类的映射关系
    在这里插入图片描述
    图中的VO相当于本文的requestDTO,而DTO相当于本文的responseDTO。写操作中三种POJO的转化流程如下:
  1. 请求的数据封装为VO
  2. 展示层把VO转换为服务层方法所需的DTO,传送给服务层
  3. 服务层首把DTO转换为领域层方法所需的DO,调用DO的业务方法完成具体业务
  4. 服务层把DO转换为持久层方法所需的PO(可以使用ORM工具,也可以不用),调用持久层的的方法完成持久化操作

强化理解:application中的方法需要的参数类型为DTO,domain中的方法需要的参数类型为DO,而dao中的方法需要的参数类型为PO。当上层调用下层时,需要将数据转换为下层方法所需的数据类型,下层返回结果给上层时,也需返回上层所需的数据类型。

参考博客推荐

MVC与三层架构理解
DDD-经典四层架构应用
DDD架构
领域驱动设计DDD之VO、DTO、DO和PO浅谈

  • 37
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值