您当前的位置:首页 > 电脑百科 > 程序开发 > 架构

架构师必备 - DDD之落地实践

时间:2022-08-29 13:46:03  来源:今日头条  作者:互联网架构小马哥

今天带大家认识下DDD,一个听起来很垃圾却真的很牛X的设计思想,架构师必备!

前言

在日常工作中,接手或维护的工程,大多数使用的是三层架构,即controller、service、dao三层,在使用的过程中,会遇到很多问题:

  • 面向数据建模,面向过程编程,没有真正“面向对象”
  • 只注重结果,不注重过程,service层动辄数百上千行,充斥着过程代码、胶水代码,要么臃肿、要么流水账、要不重复、要么逻辑分散,后期极难维护
  • 代码耦合严重,层与层之间互相调用、逆向调用,牵一发而动全身
  • 代码无法体现业务,在大家都不爱写注释的情况下,随着时间的推移,代码业务逻辑将无人理解,不敢改也改不动。

那么有没有一个好的解决方案呢?今天要讲的DDD就是一个不错的选择。

DDD

DDD,即领域驱动设计,完美的解决了以上问题:

  • 面向领域建模,面向对象编程,代码直接映射现实世界概念,贴近业务,离客户更近
  • 领域逻辑高内聚,符合JAVA开发原则
  • 技术细节变更如数据库、缓存、定时器等的变更对业务逻辑影响比较小,非常适合插件式架构
  • 代码可读性、可维护性更强,对后续扩展、移植等支持更好,分层更加科学

DDD的概念,在网上很容易找到,这里就不赘述了。

然而网上DDD的文章虽然很多,但大多数是理论知识,介绍的无非就是一些名词:战略设计、战术设计、核心域、支撑域、值对象、实体、聚合... 对我们实际落地却没有太多的帮助,下面介绍下我在SpringBoot中应用DDD的落地方案。

落地方案

1、代码分层

 

代码分层

  • 用户接口层:图中的api包(即controller层,我嫌controller后缀太长...)
  • 应用层:这里使用了命令模式,并且读写分离成了两个包(command、query),如果不使用命令模式可以合并成一个service包
  • 领域层:domAIn包,使用JPA(对DDD有良好的支持)
  • 基础设施层:infra包,其他所有的公用组件都放在这里,如果使用DIP依赖倒置,那么实现类也放在这里。
  • model模型:model包,用于存放不同层间传递的对象,这些对象我试过放到好些地方,最后发现还是提出来统一放在一个包下比较好(便于服务间调用时共用对象)

2、层级关系及模型传递

 

分层及调用关系

3、分层详细说明

  • api包(controller)
@Tag(name = "用户", description = "用户")
@RestController
@RequestMApping(value = "/api/sys-user")
public class SysUserApi extends BaseApi {


    @ApiResult
    @Operation(summary = "根据ID查询用户")
    @GetMapping("/{id}")
    public SysUserVo get(@PathVariable Long id) {
        return queryExecutor.execute(new SysUserByIdQry(id));
    }


    @Pagination(total = true)
    @ApiResult
    @Operation(summary = "分页查询用户")
    @GetMapping
    public List<SysUserVo> getList(SysUserQo sysUserQo) {
        return queryExecutor.execute(new SysUserListQry(sysUserQo));
    }


    @ApiResult
    @Operation(summary = "新增用户")
    @PostMapping
    public void save(@Valid @RequestBody SysUserDto sysUserDto) {
        commandExecutor.execute(new SysUserCommonCmd(sysUserDto));
    }
}

在BaseApi中封装了两个命令执行类queryExecutor和commandExecutor,调用应用层时执行不同的命令即可,无需@Autowired引入不同的服务

@ApiResult加上这个自定义注解后,对返回结果统一封装

@Pagination加上这个自定义注解后,会自动将分页参数存入线程变量,后面查询时也会自动获取分页参数,返回结果统一封装时也会加上分页信息

Qo是查询参数对象,Dto是增删改等命令参数对象,返回对象为Vo,这里要注意,Entity绝对不能暴露到这一层,需要转换为Vo再返回

在这一层中,每个方法几乎就是一行执行命令的语句,一般情况不进行业务逻辑(当然也有特殊情况咯)

  • command包
@AllArgsConstructor
public class SysDeptAddCmd implements Command<Void> {


    private SysDeptDto sysDeptDto;


    @Override
    public Void execute(Executor executor) {
        // 获取命令的接收者:领域服务
        SysDeptManager receiver = executor.getReceiver(SysDeptManager.class);
        // 对象模型转换,由DTO转为Entity,使用了MapStruct
        SysDept sysDept = SysDeptMapper.INSTANCE.toSysDept(sysDeptDto);
        // 使用JPA保存
        receiver.save(sysDept);
        return null;
    }
}

增删改命令,很薄的一层,作为一项工作的组织者,几乎没有业务逻辑,调用领域服务和充血对象方法

命令模式,实现自定义Command接口,泛型为返回值

通过属性和构造方法(使用lombok注解)接收参数

一个命令里只有一个execute方法,缺点是会产生大量的命令类,一个类相当于之前service类中的一个方法,但是这样符合了单一职责原则

通过executor.getRecerver方法获取到领域服务(manager)

DTO绝对不下探到领域层中,需要先由DTO转换为Entity(转换方法这里使用的MapStruct,以后再单独细讲)

  • query包
@AllArgsConstructor
public class SysDeptByIdQry extends CommonQry<SysDeptVo> {


    private Long id;


    @Override
    public SysDeptVo execute(Executor executor) {
        if (id == null) {
            throw new BusinessException("部门ID不能为空");
        }
        QSysDept sysDept = QSysDept.sysDept;
        return queryFactory.select(this.fields())
                .from(sysDept)
                .where(sysDept.deleted.eq(false), sysDept.id.eq(id))
                .fetchOne();
    }


    /**
     * 部门VO映射
     *
     * @return QBean<SysDeptVo>
     */
    public static QBean<SysDeptVo> fields() {
        QSysDept sysDept = QSysDept.sysDept;
        return Projections.fields(
            SysDeptVo.class,
            sysDept.deptName,
            sysDept.orderNum,
            sysDept.id
        );
    }
}

命令模式,继承自定义CommonQry基类(此类也实现了自定义的Command接口,其中引用了QueryDSL的queryFactory类,且封装了分页方法),泛型为返回值

query包中的查询命令与command包中的命令大体相同,唯一区别是query命令理论上直接查询数据库,不调用领域层

由于JPA对于复杂查询不太好用,这里强烈推荐使用QueryDSL(以后再单独细讲),图中是一个简单的使用例子

  • domain包

类较多,代码部分不一一罗列:

由Entity类自动生成数据库表,仅维护Entity类(屏蔽数据库)

设计Entity时根据实际业务灵活使用@.NEToMany、@OneToOne等注解(聚合根的概念)

聚合根不要太大,80%的情况一个聚合根中只包含一个实体(不要过度设计成大聚合根)

不要使用贫血模型,而是要面向对象,属于对象的方法要放到对象中,但是对象中不建议引入仓库repository类,需要操作数据库的方法写在领域服务manager里

业务逻辑尽量写在领域服务(manager)中,不断提取、抽象不同的方法供应用层调用

适当的使用领域事件,JPA可以在Entity中使用@DomainEvents注解来发送领域事件

心得

  • 通过DDD对业务理解更加透彻,写的代码可以更好的传达客户的业务诉求
  • 能够尽情地编写低耦合的、符合单一职责、开闭等原则、封装、继承、多态的代码,是很身心愉悦的
  • 前期相比传统架构代码量更多,开发人员前期投入更多:
  • 领域的合理划分、实体的合理设计
  • 大量的DTO、VO等数据对象
  • 大量的数据对象转换方法
  • 大量的命令类
  • ...

但是,除非是特别简单的功能,对于一个中等复杂的系统,这些前期的付出还是值得的,一张图说明:

 

小结

以上简单介绍了下我对DDD的理解和实践,并通过实际的代码展现了如何在SpringBoot中应用DDD,希望能为大家提供一个思路。

原文链接:
https://mp.weixin.qq.com/s/n2p9UmHBcuCwrWnLHgLktw



Tags:架构   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
美团外卖宣布新一轮组织架构调整:提拔多位年轻管理者,年轻化、扁平化成主基调
新浪科技讯 4月11日上午消息,继2月下旬、3月下旬两轮人员调整后,美团到店到家的组织架构调整仍在继续。近日,美团外卖以内部邮件的方式宣布了新一轮的组织调整:外卖事业部下成立...【详细内容】
2024-04-11  Search: 架构  点击:(4)  评论:(0)  加入收藏
对于微服务架构监控应该遵守的原则
随着软件交付方式的变革,微服务架构的兴起使得软件开发变得更加快速和灵活。在这种情况下,监控系统成为了微服务控制系统的核心组成部分。随着软件的复杂性不断增加,了解系统的...【详细内容】
2024-04-03  Search: 架构  点击:(5)  评论:(0)  加入收藏
大模型应用的 10 种架构模式
作者 | 曹洪伟在塑造新领域的过程中,我们往往依赖于一些经过实践验证的策略、方法和模式。这种观念对于软件工程领域的专业人士来说,已经司空见惯,设计模式已成为程序员们的重...【详细内容】
2024-03-27  Search: 架构  点击:(13)  评论:(0)  加入收藏
哈啰云原生架构落地实践
一、弹性伸缩技术实践1.全网容器化后一线研发的使用问题全网容器化后一线研发会面临一系列使用问题,包括时机、容量、效率和成本问题,弹性伸缩是云原生容器化后的必然技术选择...【详细内容】
2024-03-27  Search: 架构  点击:(10)  评论:(0)  加入收藏
京东小程序数据中心架构设计与最佳实践
一、京东小程序是什么京东小程序平台能够提供开放、安全的产品,成为品牌开发者链接京东内部核心产品的桥梁,致力于服务每一个信任我们的外部开发者,为不同开发能力的品牌商家提...【详细内容】
2024-03-27  Search: 架构  点击:(12)  评论:(0)  加入收藏
从 MySQL 到 ByteHouse,抖音精准推荐存储架构重构解读
ByteHouse是一款OLAP引擎,具备查询效率高的特点,在硬件需求上相对较低,且具有良好的水平扩展性,如果数据量进一步增长,可以通过增加服务器数量来提升处理能力。本文将从兴趣圈层...【详细内容】
2024-03-22  Search: 架构  点击:(25)  评论:(0)  加入收藏
全程回顾黄仁勋GTC演讲:Blackwell架构B200芯片登场
北京时间3月19日4时-6时,英伟达创始人黄仁勋在美国加州圣何塞SAP中心登台,发表GTC 2024的主题演讲《见证AI的变革时刻》。鉴于过去一年多时间里AI带来的生产力变革,以及英伟达...【详细内容】
2024-03-19  Search: 架构  点击:(17)  评论:(0)  加入收藏
高并发架构设计(三大利器:缓存、限流和降级)
软件系统有三个追求:高性能、高并发、高可用,俗称三高。本篇讨论高并发,从高并发是什么到高并发应对的策略、缓存、限流、降级等。引言1.高并发背景互联网行业迅速发展,用户量剧...【详细内容】
2024-03-13  Search: 架构  点击:(6)  评论:(0)  加入收藏
有了LLM,所有程序员都将转变为架构师?
编译 | 言征 出品 | 51CTO技术栈(微信号:blog51cto)生成式人工智能是否会取代人类程序员?可能不会。但使用生成式人工智能的人类可能会,可惜的是,现在还不是时候。目前,我们正在见...【详细内容】
2024-03-07  Search: 架构  点击:(19)  评论:(0)  加入收藏
如何判断架构设计的优劣?
架构设计的基本准则是非常重要的,它们指导着我们如何构建可靠、可维护、可测试的系统。下面是这些准则的转换表达方式:简单即美(KISS):KISS原则的核心思想是保持简单。在设计系统...【详细内容】
2024-02-20  Search: 架构  点击:(36)  评论:(0)  加入收藏
▌简易百科推荐
对于微服务架构监控应该遵守的原则
随着软件交付方式的变革,微服务架构的兴起使得软件开发变得更加快速和灵活。在这种情况下,监控系统成为了微服务控制系统的核心组成部分。随着软件的复杂性不断增加,了解系统的...【详细内容】
2024-04-03  步步运维步步坑    Tags:架构   点击:(5)  评论:(0)  加入收藏
大模型应用的 10 种架构模式
作者 | 曹洪伟在塑造新领域的过程中,我们往往依赖于一些经过实践验证的策略、方法和模式。这种观念对于软件工程领域的专业人士来说,已经司空见惯,设计模式已成为程序员们的重...【详细内容】
2024-03-27    InfoQ  Tags:架构模式   点击:(13)  评论:(0)  加入收藏
哈啰云原生架构落地实践
一、弹性伸缩技术实践1.全网容器化后一线研发的使用问题全网容器化后一线研发会面临一系列使用问题,包括时机、容量、效率和成本问题,弹性伸缩是云原生容器化后的必然技术选择...【详细内容】
2024-03-27  哈啰技术  微信公众号  Tags:架构   点击:(10)  评论:(0)  加入收藏
DDD 与 CQRS 才是黄金组合
在日常工作中,你是否也遇到过下面几种情况: 使用一个已有接口进行业务开发,上线后出现严重的性能问题,被老板当众质疑:“你为什么不使用缓存接口,这个接口全部走数据库,这怎么能扛...【详细内容】
2024-03-27  dbaplus社群    Tags:DDD   点击:(12)  评论:(0)  加入收藏
高并发架构设计(三大利器:缓存、限流和降级)
软件系统有三个追求:高性能、高并发、高可用,俗称三高。本篇讨论高并发,从高并发是什么到高并发应对的策略、缓存、限流、降级等。引言1.高并发背景互联网行业迅速发展,用户量剧...【详细内容】
2024-03-13    阿里云开发者  Tags:高并发   点击:(6)  评论:(0)  加入收藏
如何判断架构设计的优劣?
架构设计的基本准则是非常重要的,它们指导着我们如何构建可靠、可维护、可测试的系统。下面是这些准则的转换表达方式:简单即美(KISS):KISS原则的核心思想是保持简单。在设计系统...【详细内容】
2024-02-20  二进制跳动  微信公众号  Tags:架构设计   点击:(36)  评论:(0)  加入收藏
详解基于SpringBoot的WebSocket应用开发
在现代Web应用中,实时交互和数据推送的需求日益增长。WebSocket协议作为一种全双工通信协议,允许服务端与客户端之间建立持久性的连接,实现实时、双向的数据传输,极大地提升了用...【详细内容】
2024-01-30  ijunfu  今日头条  Tags:SpringBoot   点击:(18)  评论:(0)  加入收藏
PHP+Go 开发仿简书,实战高并发高可用微服务架构
来百度APP畅享高清图片//下栽のke:chaoxingit.com/2105/PHP和Go语言结合,可以开发出高效且稳定的仿简书应用。在实现高并发和高可用微服务架构时,我们可以采用一些关键技术。首...【详细内容】
2024-01-14  547蓝色星球    Tags:架构   点击:(115)  评论:(0)  加入收藏
GraalVM与Spring Boot 3.0:加速应用性能的完美融合
在2023年,SpringBoot3.0的发布标志着Spring框架对GraalVM的全面支持,这一支持是对Spring技术栈的重要补充。GraalVM是一个高性能的多语言虚拟机,它提供了Ahead-of-Time(AOT)编...【详细内容】
2024-01-11    王建立  Tags:Spring Boot   点击:(124)  评论:(0)  加入收藏
Spring Boot虚拟线程的性能还不如Webflux?
早上看到一篇关于Spring Boot虚拟线程和Webflux性能对比的文章,觉得还不错。内容较长,抓重点给大家介绍一下这篇文章的核心内容,方便大家快速阅读。测试场景作者采用了一个尽可...【详细内容】
2024-01-10  互联网架构小马哥    Tags:Spring Boot   点击:(118)  评论:(0)  加入收藏
站内最新
站内热门
站内头条