基于DDD的编码实践

分层设计

领域驱动设计(Domain-driven design, DDD) 作为一种复杂软件系统的应对方案,在设计和编码提供了一种新的解决方式,即领域驱动,要求程序员在设计和编码时从领域专家的角度出发来实现架构/代码,做到代码即业务。同时利用各种方式拆解复杂模块,常用的方式有拆分子域、构建富血对象。

设计时,需要建立统一语言,确保领域中的业务概念处于同一个限界上下文,比如在一套电商系统中,用户买了一个东西,对应后台有一个订单,此时订单指代订单域的一项数据,当该订单需要发货时,在物流域中也会接受订单域输入并产生发货订单,此时,物流域的订单和订单域的订单就不处于一个限界上下文。建立统一语言有助于后续的产品和研发之间的高效沟通,打破代码和业务的语义鸿沟。领域模型的设计方法有 用例分析、事件风暴,领域模型需要提取出核心功能,并保证一定的扩展性,往往该过程是最重要也是最困难的。

进入编码阶段,构建聚合、聚合根、实体、值对象。虽然领域层与业务逻辑强关联,但是为了技术实现,在设计时也会有一些妥协,如,聚合不宜设计的过大,聚合的设计需要考虑实体之间的一致性要求,同时有一些事务、锁的使用在某些时候会侵入领域层(并非不能这样,实践中往往在实现时会借鉴DDD的思想,但不会全套照搬);除此之外,结合事件驱动的方式,可以让领域层代码保留一定的扩展性,实现上可以参考文章SpringEvent扩展性利器;领域层作为核心不应该依赖具体实现,借鉴六边形架构,领域层中定义了仓储协议(Repository接口),业务逻辑只需要从仓储接口中获取数据,至于实现领域层并不关系,而具体的实现由其他模块如infrastructure层来实现;同时,在实际处理输入时(http,rpc,job…)通常涉及与其他域的交互,DDD中通过构建防腐层来应对外部变化。

最终得到的代码分层结构如下图,Maven archetype代码参见:ddd-spring-web-maven-archetype:

在这里插入图片描述

编码tips

构建富血实体

经典的MVC架构基于贫血对象构建,贫血对象只作为data class,其业务含义丢失,通过构建富血对象将业务实体的
逻辑内聚,不在分散在各个service中,一是业务含义清晰,二是能够单点控制。

比如,判断ExpressAggregate物流聚合的发货状态,其含有字段如下:

@Data
public class ExpressAggregate {
    
    private ExpressNumber expressNumber;
    // 状态
    private ExpressStatus expressStatus;
    ...
}

基于贫血对象,判断该物流实体是否发货需要在service中调用ExpressAggregate做判断:

ExpressAggregate expressAggregate = ...;
if (Objects.equals(express.status,...)){
  // bisiness logic
  ...
}

而基于富血对象,我们可以将是否发货的逻辑内置与ExpressAggregate中:

@Data
public class ExpressAggregate {

    private ExpressNumber expressNumber;
    private ExpressStatus expressStatus;
    ...

    /**
     * 判断是否发货
     * @return
     */
    public boolean hasSent() {
        return Objects.equals(this.expressStatus, ExpressStatus.SENT)
                   || Objects.equals(this.expressStatus, ExpressStatus.RECEIVED)
                   || Objects.equals(this.expressStatus, ExpressStatus.RETURN);
    }
}

这样,调用方直接使用 expressAggregate.hasSent() 即可知道结果,避免了判断逻辑散落各处。

值对象不可变

使用值对象表示无唯一标识(id)含义的实体,其各项属性相等即视为同一个值对象,因此值对象不可变。在实现层面,
值对象不应有setter:

// 无setter
@Getter
@AllArgsConstructor(staticName = "of")
public class ExpressNumber {
    private String expressNumber;
}

// usage
ExpressNumber expressNum = ExpressNumber.of("abc123");

相比于直接使用String expressNumber , 在业务代码中使用ExpressNumber具有更强的业务含义,且作为方法入参时不易与其他String类型参数弄混。

层间对象转换

不同层的对象不应混用,层间调用应使用转换器转换,转换工作由谁来做?谁有转换需求谁来做。

CQRS

CQRS(Command Query Responsibility Segregation) 将输入分为 Command 和 Query,
Command作为变更系统状态的输入由领域层(聚合根)处理,而Query可不走领域层。

在这里插入图片描述

图片来源:Axon Framework : Architecture Overview

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/721193.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Canvas->不依赖View的Canvas,创建Canvas绘制Bitmap的某个区域

XML文件 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:o…

【Java】已解决java.lang.ArrayIndexOutOfBoundsException异常

文章目录 一、问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决java.lang.ArrayIndexOutOfBoundsException异常 一、问题背景 java.lang.ArrayIndexOutOfBoundsException 是 Java 中一个非常常见的运行时异常&#xff0c;它表明程序试图访问数…

POSIX信号量以及读写者模型/环形队列

POSIX信号量 POSIX信号量和SystemV信号量作用相同&#xff0c;都是用于同步操作&#xff0c;达到无冲突的访问共享资源目的。 但POSIX可以用于线程间同步,他的本质是一个计数器,对共享资源进行等待或释放 POSIX信号量的重要概念 1.计数器:信号量维护一个计数器&#xff0c;它…

Leaflet地图实例

ReactTypeScript实例&#xff1a; import React, { useEffect, useRef } from "react"; import * as L from "leaflet"; import "leaflet/dist/leaflet.css";const App: React.FC () > {const mapRef useRef<HTMLDivElement>(null);…

TestProject Python SDK入门

2024软件测试面试刷题&#xff0c;这个小程序&#xff08;永久刷题&#xff09;&#xff0c;靠它快速找到工作了&#xff01;&#xff08;刷题APP的天花板&#xff09;-CSDN博客跳槽涨薪的朋友们有福了&#xff0c;今天给大家推荐一个软件测试面试的刷题小程序。​编辑https://…

达梦导入导出

针对导出数据库表结构通常有 3 种方法&#xff1a; 使用 DTS 导出 打开 DTS 迁移工具&#xff0c;选择【DM-->SQL】并链接到数据库中&#xff0c;如下图所示&#xff1a; 添加定义脚本&#xff0c;并选择【迁移范围】&#xff08;仅迁移对象定义&#xff09;&#xff0c;如…

后端开发中缓存的作用以及基于Spring框架演示实现缓存

缓存的作用及演示 现在我们使用的程序都是通过去数据库里拿数据然后展示的 长期对数据库进行数据访问 这样数据库的压力会越来越大 数据库扛不住了 创建了一个新的区域 程序访问去缓存 缓存区数据库 缓存里放数据 有效降低数据访问的压力 我们首先进行一个演示 为了演示…

MySQL事务、数据库的存储引擎

1. 事务的概念 定义&#xff1a;事务就是一组数据库操作序列&#xff08;包含一个或多个SQL操作命令&#xff09;&#xff0c;事务会把所有操作看作是一个不可分割的整体向数据库系统提交或撤销操作&#xff0c;所有操作要么都执行&#xff0c;要么都不执行。 1.1事务的 ACID …

嵌入式学习记录6.13(qt day1)

一.思维导图 二.练习&#xff08;简单模拟tim界面&#xff09; 2.1代码 mywidget.cpp #include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {this->setWindowTitle("Tim");this->setWindowIcon(QIcon("C:\\Users\\zy\…

Vue61-消息订阅与发布-任意组件之间的通信

一、原理图 原生的JS不能实现订阅与发布&#xff0c;要借助第三方库&#xff1a;pubsub-js&#xff08;任何一个框架都能用&#xff01;&#xff09; 二、案例实现 school组件&#xff0c;需要数据&#xff08;订阅消息&#xff09;&#xff0c;student组件提供数据&#xff0…

现代互联网应用中的HTTPS技术

现代互联网应用中的HTTPS技术 在现代互联网应用中&#xff0c;网上诈骗、垃圾邮件和数据泄露等现象时有发生。为了保障数据安全&#xff0c;我们通常选择采用HTTPS技术。甚至在iOS开发中&#xff0c;调用接口必须是HTTPS接口。现在&#xff0c;部分浏览器也开始强制要求网站必…

这个开源软件,送给爱读书的你!!【送源码】

对于喜欢阅读的人来说&#xff0c;一定经历过从一本厚厚的修仙书籍到MP3、MP4的阅读时代&#xff0c;再到现今的手机软件。 但是现在的阅读软件经常会遇见以下问题&#xff1a;比如广告弹窗太多&#xff0c;排版乱&#xff0c;甚至很多的APP都进入会员时代&#xff0c;再加上一…

【RK3588/算能/Nvidia智能盒子】挑战「无电无网」部署AI算法,守护大亚湾荃美石化码头工地安全

“万顷碧波之上&#xff0c;一座千米钢栈桥如蛟龙出水&#xff0c;向大海蜿蜒。钢栈桥上的项目建设者正在加紧作业&#xff0c;为助推惠州大亚湾加快建设成为世界级绿色石化基地全力奋战。”这是不久前北京日报对大亚湾惠州港荃湾港区荃美石化码头工地的描述。 △ 图片来源于北…

C#——文件读取FileStream类详情

文件读取FileStream类 一个文件进行读写的时候&#xff0c;会变成一个文件流 FileStream类输入流 用于从文件进行读取文件。输出流&#xff0c;向文件写入的操作 FilleStream用于文件当中任何位置的读写 此文章借鉴与&#xff1a;C#教程&#xff08;非常详细&#xff09; Fil…

基于minhook的Windows HOOK

MinHook是一个基于微软Detours技术的可移植Hook库&#xff0c;它允许开发者在运行时更改函数定义&#xff0c;而无需修改原始函数代码。以下是关于MinHook的详细介绍&#xff1a; 基本概念 定义&#xff1a;MinHook使用内存污染和跳转技术来实现Hook&#xff0c;使得开发者能…

2024 年值得关注的 9 个最佳开源大语言模型

一、简述 开源模型在提供创新方面发挥着至关重要的作用&#xff0c;同时为开发人员、爱好者和开发人员提供了深入研究其复杂之处并对其进行微调以执行特定任务的机会。 我们将探讨一些正在开拓新市场前景并带来其独特能力和优势的顶级开源 LLM。 二、开源模型清单 1.GPT-NeoX…

【AICFD教程】汽车外气动仿真,小白学CFD的入门案例

【视频教程】 【教程】汽车外气动仿真&#xff0c;小白学CFD的入门案例 【文字教程】 1. 案例背景 1.1 学习目标 本案例针对某汽车仿真模型&#xff0c;在车速为40m/s时进行了汽车外流场的数值模拟。 本案例教程旨在演示AICFD中以下场景与功能的操作&#xff1a; a. 单域外…

【Linux Vim的保姆级教程】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

统计学一(术语,正态)

目录 一&#xff0c;常用术语 二&#xff0c;正态分布&#xff08;Normal Distribution&#xff09; 三&#xff0c;中心极限定理(Central Limit Theorem) 一&#xff0c;常用术语 population(族群)&#xff1a;要统计的总的 populationSize(族群数量)&#xff1a;要统计的总…

CleanMyMac X for Mac系统优化垃圾清理软件卸载 工具(小白轻松上手,简单易学)

Mac分享吧 文章目录 效果一、准备工作二、开始安装1、双击运行软件&#xff0c;将其从左侧拖入右侧文件夹中&#xff0c;等待安装完毕2、启动台显示软件图标&#xff0c;表示安装成功 三、运行测试1、打开软件&#xff0c;配置2、授权&#xff0c;允许完全磁盘访问 安装完成&a…