DDD架构及相关概念

2025-03-21 22:18:27 4


贫血模型和充血模型

贫血模型只有属性

public class RoleId {
    private Long value;
}


充血模型有属性也有行为(方法)

public class RoleId {

    private final Long value;


    public void print() {
        System.out.println("getValue:" + value);
    }
}

贫血三层模型

Controller + Service (处理业务逻辑并调用DAO接口操作数据库) + DAO (包括贫血Model)

DDD经典四层架构



用户接口层

仅将应用层的方法向外暴露

应用层

协调领域模型和基础设施层完成完整业务逻辑

领域层

充血模型 实现具体业务逻辑

领域模型的查询和保存接口定义在领域层, 具体实现在基础设施层

基础设施层

操作db/cache/mq等基础设施



实体和值对象

实体

领域模型, 具有唯一标识

值对象

也是领域模型, 没有唯一标识

聚合和聚合根

聚合

领域模型的对象不会孤立的存在, 往往存在引用关系, 形成一颗对象树. 聚合内的对象是强一致的.

聚合根

这颗对象树的根, 聚合根必定是实体

领域服务

领域服务是领域模型的一种表现形式, 是领域模型的一部分

领域服务是无状态的

当领域中的操作涉及到多个聚合根, 或者不是实体和值对象的自然职责时, 应该定义一个独立的接口

比如导出用户列表的操作, 涉及到多个聚合根

不应该滥用领域服务, 否则将回到贫血模型0

防腐层

用于隔离外部上下文

比如领域模型中调用了第三方接口, 哪天第三方接口的方法签名/入参/出参都发生了改变, 那么该领域模型也需要进行改变.

领域事件

领域事件是聚合中已发生的事实, 代表聚合内以及发生的业务操作和状态变化

如果需要强一致性的事件通知, 可以把发布事件处理事件的逻辑抽出来做成领域服务, 而不是在聚合内处理

CQRS

Command Query Responsibility Segregation 命令和查询责任分离

通过使用不同的模型, 分别实现修改操作, 与查询操作, 达到命令和查询分离的目的

在ddd中的, 应用层根据职责被分为两部分: 命令应用服务和查询应用服务

查询操作可以绕过领域模型

事件溯源

是一种将所有的领域事件存储到事件存储中, 并通过重放历史事件来还原领域对象状态的模式

在一些数据变更非常重要的业务场景,如财务、金融领域,可能会使用这种数据持久化方式

可以用拉链法处理事件溯源

事件风暴

事件风暴建模方法: 通过收集所有相关方关注的领域事件, 逐步提取出状态变更的场景/对应的角色/操作, 以提取出对应的聚合, 再划分出限界上下文, 完成建模


ddd实战小项目


https://github.com/MQPearth/ddd-blog

DDD架构及相关概念

DDD架构及相关概念

贫血模型和充血模型贫血模型只有属性public class RoleId { private Long value; }充血模型有属性也有行为(方法)贫血三层模型Controller + Service (处理业务逻辑并调用DAO接口操作数据库) + DAO (包括贫血Model)DDD经典
2025-03-21

freemarker 时间显示不正常 设置时区

项目在本地开发的时候显示正常,部署上服务器就一直差8个小时,最后发现freemarker官方文档有这样的说明time_zone:时区的名称来显示并格式化时间。 默认情况下,使用JVM的时区。 也可以是 Java 时区 API 接受的值,或者 "JVM default" (从 FreeMarker 2
2020-03-28
IDEA 2019.1 xml 不高亮

IDEA 2019.1 xml 不高亮

前几天更新了idea后,发现xml里的代码都没有了高亮,变得跟记事本一个德性了打开setting ,搜索 File Types,找到xml项, 查看下方的匹配格式,果然没有xml,(idea真是厉害)点击右方的+,输入*.xml,点击ok,解决问题
2020-03-28

npm install 淘宝镜像

npm install --registry=https://registry.npm.taobao.org
2020-03-28
Java中方法的参数传递机制

Java中方法的参数传递机制

来看一段代码 public class Man { private String name; private Integer age; public String getName() { return name; } publi
2020-03-28
基于自定义注解手写权限控制

基于自定义注解手写权限控制

方法一: AOP 方法二: 拦截器项目结构项目依赖<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-w
2020-03-28

Docker 部署 详细全过程 附代码

Docker 部署本站 全过程环境:CentOS7.61. 安装Docker其他版本CentOS可以参考这个https://help.aliyun.com/document_detail/187598.html查看本机内核版本,内核版本需高于 3.10uname -r 确保 yum 包最新yum u
2020-03-28

SpringBoot 启动普通java工程

引入依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.0.9</version> </dependency>
2020-03-28

Vue.js DOM操作

<template> <input type="button" @click="reply($event)" value="回复"> </template> export default { methods: { replyFun(e) {
2020-03-29
CentOS7编译调试OpenJDK12

CentOS7编译调试OpenJDK12

1. 下载源码https://hg.openjdk.java.net/jdk/jdk12点击左侧的browse,再点击zip,就可以下载zip格式的源码压缩包。unzip xxx.zip 解压文件2. 安装jdkyum install java-11-openjdk-devel -y3. 运行con
2020-04-23
编写自己的Spring Boot Starter

编写自己的Spring Boot Starter

1.新建一个maven项目命名规则统一是xxx-spring-boot-starter完整pom.xml<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"
2020-06-29