DDD专题案例一《初识领域驱动设计DDD落地方案》

本文涉及的产品
云原生内存数据库 Tair,内存型 2GB
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
简介: DDD(Domain-Driven Design 领域驱动设计)是由Eric Evans最先提出,目的是对软件所涉及到的领域进行建模,以应对系统规模过大时引起的软件复杂性的问题。整个过程大概是这样的,开发团队和领域专家一起通过 通用语言(Ubiquitous Language)去理解和消化领域知识,从领域知识中提取和划分为一个一个的子领域(核心子域,通用子域,支撑子域),并在子领域上建立模型,再重复以上步骤,这样周而复始,构建出一套符合当前领域的模型。

前言介绍

DDD(Domain-Driven Design 领域驱动设计)是由Eric Evans最先提出,目的是对软件所涉及到的领域进行建模,以应对系统规模过大时引起的软件复杂性的问题。整个过程大概是这样的,开发团队和领域专家一起通过 通用语言(Ubiquitous Language)去理解和消化领域知识,从领域知识中提取和划分为一个一个的子领域(核心子域,通用子域,支撑子域),并在子领域上建立模型,再重复以上步骤,这样周而复始,构建出一套符合当前领域的模型。

0.jpg

开发目标

依靠领域驱动设计的设计思想,通过事件风暴建立领域模型,合理划分领域逻辑和物理边界,建立领域对象及服务矩阵和服务架构图,定义符合DDD分层架构思想的代码结构模型,保证业务模型与代码模型的一致性。通过上述设计思想、方法和过程,指导团队按照DDD设计思想完成微服务设计和开发。

1、拒绝泥球小单体、拒绝污染功能与服务、拒绝一加功能排期一个月

2、架构出高可用极易符合互联网高速迭代的应用服务

3、物料化、组装化、可编排的服务,提高人效

服务架构

1.jpg

  • 应用层{application}
  • 应用服务位于应用层。用来表述应用和用户行为,负责服务的组合、编排和转发,负责处理业务用例的执行顺序以及结果的拼装。
  • 应用层的服务包括应用服务和领域事件相关服务。
  • 应用服务可对微服务内的领域服务以及微服务外的应用服务进行组合和编排,或者对基础层如文件、缓存等数据直接操作形成应用服务,对外提供粗粒度的服务。
  • 领域事件服务包括两类:领域事件的发布和订阅。通过事件总线和消息队列实现异步数据传输,实现微服务之间的解耦。
  • 领域层{domain}
  • 领域服务位于领域层,为完成领域中跨实体或值对象的操作转换而封装的服务,领域服务以与实体和值对象相同的方式参与实施过程。
  • 领域服务对同一个实体的一个或多个方法进行组合和封装,或对多个不同实体的操作进行组合或编排,对外暴露成领域服务。领域服务封装了核心的业务逻辑。实体自身的行为在实体类内部实现,向上封装成领域服务暴露。
  • 为隐藏领域层的业务逻辑实现,所有领域方法和服务等均须通过领域服务对外暴露。
  • 为实现微服务内聚合之间的解耦,原则上禁止跨聚合的领域服务调用和跨聚合的数据相互关联。
  • 基础层{infrastructrue}
  • 基础服务位于基础层。为各层提供资源服务(如数据库、缓存等),实现各层的解耦,降低外部资源变化对业务逻辑的影响。
  • 基础服务主要为仓储服务,通过依赖反转的方式为各层提供基础资源服务,领域服务和应用服务调用仓储服务接口,利用仓储实现持久化数据对象或直接访问基础资源。
  • 接口层{interfaces}
  • 接口服务位于用户接口层,用于处理用户发送的Restful请求和解析用户输入的配置文件等,并将信息传递给应用层。

开发环境

1、jdk1.8【jdk1.7以下只能部分支持netty】

2、springboot 2.0.6.RELEASE

3、idea + maven

代码示例

1itstack-demo-ddd-01
 2└── src
 3    ├── main
 4    │   ├── java
 5    │   │   └── org.itstack.demo
 6    │   │       ├── application
 7    │   │       │    ├── event
 8    │   │       │    │   └── ApplicationRunner.java  
 9    │   │       │    └── service
10    │   │       │        └── UserService.java    
11    │   │       ├── domain
12    │   │       │    ├── model
13    │   │       │    │   ├── aggregates
14    │   │       │    │   │   └── UserRichInfo.java   
15    │   │       │    │   └── vo
16    │   │       │    │       ├── UserInfo.java   
17    │   │       │    │       └── UserSchool.java 
18    │   │       │    ├── repository
19    │   │       │    │   └── IuserRepository.java    
20    │   │       │    └── service
21    │   │       │        └── UserServiceImpl.java    
22    │   │       ├── infrastructure
23    │   │       │    ├── dao
24    │   │       │    │   ├── impl
25    │   │       │    │   │   └── UserDaoImpl.java    
26    │   │       │    │   └── UserDao.java    
27    │   │       │    ├── po
28    │   │       │    │   └── UserEntity.java 
29    │   │       │    ├── repository
30    │   │       │    │   ├── mysql
31    │   │       │    │   │   └── UserMysqlRepository.java
32    │   │       │    │   ├── redis
33    │   │       │    │   │   └── UserRedisRepository.java        
34    │   │       │    │   └── UserRepository.java 
35    │   │       │    └── util
36    │   │       │        └── RdisUtil.java
37    │   │       ├── interfaces
38    │   │       │    ├── dto
39    │   │       │    │   └── UserInfoDto.java    
40    │   │       │    └── facade
41    │   │       │        └── DDDController.java
42    │   │       └── DDDApplication.java
43    │   ├── resources    
44    │   │   └── application.yml
45    │   └── webapp    
46    │       └── WEB-INF
47    │            └── index.jsp   
48    └── test
49         └── java
50             └── org.itstack.demo.test
51                 └── ApiTest.java

演示部分重点代码块,完整代码下载关注公众号;bugstack虫洞栈 | 回复DDD落地

application/UserService.java | 应用层用户服务,领域层服务做具体实现

1/**
 2 * 应用层用户服务
 3 * 虫洞栈:https://bugstack.cn
 4 * 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
 5 * Create by fuzhengwei on @2019
 6 */
 7public interface UserService {
 8
 9    UserRichInfo queryUserInfoById(Long id);
10
11}

domain/repository/IuserRepository.java | 领域层资源库,由基础层实现

1/**
 2 * 虫洞栈:https://bugstack.cn
 3 * 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
 4 * Create by fuzhengwei on @2019
 5 */
 6public interface IUserRepository {
 7
 8    void save(UserEntity userEntity);
 9
10    UserEntity query(Long id);
11
12}

domain/service/UserServiceImpl.java | 应用层实现类,应用层是很薄的一层可以只做服务编排

1/**
 2 * 虫洞栈:https://bugstack.cn
 3 * 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
 4 * Create by fuzhengwei on @2019
 5 */
 6@Service("userService")
 7public class UserServiceImpl implements UserService {
 8
 9    @Resource(name = "userRepository")
10    private IUserRepository userRepository;
11
12    @Override
13    public UserRichInfo queryUserInfoById(Long id) {
14
15        // 查询资源库
16        UserEntity userEntity = userRepository.query(id);
17
18        UserInfo userInfo = new UserInfo();
19        userInfo.setName(userEntity.getName());
20
21        // TODO 查询学校信息,外部接口
22        UserSchool userSchool_01 = new UserSchool();
23        userSchool_01.setSchoolName("振华高级实验中学");
24
25        UserSchool userSchool_02 = new UserSchool();
26        userSchool_02.setSchoolName("东北电力大学");
27
28        List<UserSchool> userSchoolList = new ArrayList<>();
29        userSchoolList.add(userSchool_01);
30        userSchoolList.add(userSchool_02);
31
32        UserRichInfo userRichInfo = new UserRichInfo();
33        userRichInfo.setUserInfo(userInfo);
34        userRichInfo.setUserSchoolList(userSchoolList);
35
36        return userRichInfo;
37    }
38
39}

infrastructure/po/UserEntity.java | 数据库对象类

1/**
 2 * 数据库实体对象;用户实体
 3 * 虫洞栈:https://bugstack.cn
 4 * 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
 5 * Create by fuzhengwei on @2019
 6 */
 7public class UserEntity {
 8
 9    private Long id;
10    private String name;
11
12    get/set ...
13}

infrastructrue/repository/UserRepository.java | 领域层定义接口,基础层资源库实现

1/**
 2 * 虫洞栈:https://bugstack.cn
 3 * 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
 4 * Create by fuzhengwei on @2019
 5 */
 6@Repository("userRepository")
 7public class UserRepository implements IUserRepository {
 8
 9    @Resource(name = "userMysqlRepository")
10    private IUserRepository userMysqlRepository;
11
12    @Resource(name = "userRedisRepository")
13    private IUserRepository userRedisRepository;
14
15    @Override
16    public void save(UserEntity userEntity) {
17        //保存到DB
18        userMysqlRepository.save(userEntity);
19
20        //保存到Redis
21        userRedisRepository.save(userEntity);
22    }
23
24    @Override
25    public UserEntity query(Long id) {
26
27        UserEntity userEntityRedis = userRedisRepository.query(id);
28        if (null != userEntityRedis) return userEntityRedis;
29
30        UserEntity userEntityMysql = userMysqlRepository.query(id);
31        if (null != userEntityMysql){
32            //保存到Redis
33            userRedisRepository.save(userEntityMysql);
34            return userEntityMysql;
35        }
36
37        // 查询为NULL
38        return null;
39    }
40
41}

interfaces/dto/UserInfoDto.java | DTO对象类,隔离数据库类

1/**
 2 * 虫洞栈:https://bugstack.cn
 3 * 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
 4 * Create by fuzhengwei on @2019
 5 */
 6public class UserInfoDto {
 7
 8    private Long id;        // ID
 9
10    public Long getId() {
11        return id;
12    }
13
14    public void setId(Long id) {
15        this.id = id;
16    }
17
18}

interfaces/facade/DDDController.java | 门面接口

1/**
 2 * 虫洞栈:https://bugstack.cn
 3 * 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
 4 * Create by fuzhengwei on @2019
 5 */
 6@Controller
 7public class DDDController {
 8
 9    @Resource(name = "userService")
10    private UserService userService;
11
12    @RequestMapping("/index")
13    public String index(Model model) {
14        return "index";
15    }
16
17    @RequestMapping("/api/user/queryUserInfo")
18    @ResponseBody
19    public ResponseEntity queryUserInfo(@RequestBody UserInfoDto request) {
20        return new ResponseEntity<>(userService.queryUserInfoById(request.getId()), HttpStatus.OK);
21    }
22
23}

综上总结

  • 以上基于DDD一个基本入门的结构演示完成,实际开发可以按照此模式进行调整。
  • 目前这个架构分层还不能很好的进行分离,以及层级关系的引用还不利于扩展。
  • 后续会持续完善以及可以组合搭建RPC框架等,让整个架构更利于互联网开发。
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
设计模式 缓存 自然语言处理
DDD领域驱动设计如何进行工程化落地
DDD领域驱动设计到底如何进行实际的工程化落地,为什么要进行领域分层?本文主要围绕DDD领域分层,设计了可落地的工程结构。
DDD领域驱动设计如何进行工程化落地
|
2月前
|
数据库
DDD架构浅谈
DDD架构浅谈
50 4
|
消息中间件 开发者
DDD领域驱动设计实战(六)-领域服务(上)
DDD领域驱动设计实战(六)-领域服务
369 0
DDD领域驱动设计实战(六)-领域服务(上)
|
消息中间件 JavaScript 小程序
领域驱动设计(DDD)的几种典型架构介绍
领域驱动设计(DDD)的几种典型架构介绍
|
Web App开发 机器学习/深度学习 数据可视化
OneCode 领域驱动设计(DDD)技术实践(一)
OneCode-DSM(以下简称DSM)工具集是建立是以OneCode低代码引擎为基础专注于低代码建模应用的高阶建模工具。 在OneCode引擎中,出了为普通用户提供无代码的拖动设计器,低代码的业务逻辑编排器,之外还提供了供专业业务领域专家的使用的DSM建模工具。
|
敏捷开发 架构师 领域建模
别吵,可落地的DDD!
别吵,可落地的DDD!
436 0
|
Java API 领域建模
领域驱动设计(DDD)-简单落地
一、序言     领域驱动设计是一种解决业务复杂性的设计思想,不是一种标准规则的解决方法。在本文中的实战示例可能会与常见的DDD规则方法不太一样,是简单、入门级别,新手可以快速实践版的DDD。如果不熟悉DDD设计思想可看下基础思想篇 二、设计阶段     领域建模设计阶段常见的方法有 四色建模法、EventSourcing等 推荐一篇博文正确理解领域建
11837 1
|
设计模式 JSON 缓存
|
存储 敏捷开发 前端开发
DDD 是如何落地到数据库设计的?
DDD运用在数据库设计实战
309 0
DDD 是如何落地到数据库设计的?
|
设计模式 领域建模 数据库
DDD领域驱动设计落地实践系列:初识DDD
笔者在经历的很多项目中都使用了DDD领域驱动设计进行架构设计,尤其是在业务梳理、中台规划以及微服务划分等方面,DDD是重要的架构设计方法论,对平时的架构设计有非常好的指导作用。从本文开始笔者将通过一系列的文章阐述自己对于DDD的理解以及如何在项目实战中落地实践DDD。本文作为系列文章的开端,主要和大家聊聊DDD的一些基本概念以及常用方法。
DDD领域驱动设计落地实践系列:初识DDD