DDD专题案例一《初识领域驱动设计DDD落地》 -- 知识铺
领域驱动设计(DDD)概述
领域驱动设计(Domain-Driven Design,简称DDD)是一种以领域为中心的软件开发方法论。它由Eric Evans提出,旨在解决软件系统规模扩大带来的复杂性问题。DDD的核心在于通过建模来理解和表达业务领域知识,从而设计出高内聚、低耦合、具有良好扩展性的软件架构。
DDD的起源与发展
DDD的历史可以追溯到20世纪90年代,但随着微服务架构的兴起,DDD再次成为软件开发领域的热点。微服务架构强调服务的独立性和自治性,与DDD的理念不谋而合。
DDD的核心概念
- 通用语言(Ubiquitous Language):开发团队与领域专家共同使用的语言,以确保对业务概念的一致理解。
- 子领域划分:将业务领域划分为核心子域、通用子域和支撑子域,以识别关键业务价值和功能。
- 领域模型:基于领域知识的抽象,用于指导软件设计和开发。
DDD实战落地策略
本专题将通过分章节的方式,设计不同的架构模型,并结合实战案例,帮助读者深入理解DDD的应用。学习DDD并将其应用于实际项目,是快速提升应用级开发能力的途径。
结语
通过DDD,我们能够构建出更加符合业务需求的软件系统。Hi HelloWorld!我们正站在应用级开发的新起点。
微服务设计与开发目标
领域驱动设计(DDD)应用
依靠领域驱动设计的设计思想,我们致力于通过事件风暴建立领域模型,合理划分领域逻辑和物理边界。以下是我们的设计和开发策略:
1. 领域模型构建- 利用事件风暴方法,建立清晰的领域模型。- 确保领域逻辑与物理边界的合理划分。
2. 领域对象和服务矩阵- 定义领域对象,明确其职责和行为。- 构建服务矩阵,关联领域对象与服务。
3. 服务架构图- 绘制服务架构图,展示各服务间的关系和交互。
4. DDD分层架构- 遵循DDD分层架构思想,定义代码结构模型。- 保证业务模型与代码模型的一致性。
开发原则
1. 避免单体应用- 拒绝泥球小单体,确保系统的模块化和可维护性。
2. 功能与服务分离- 拒绝功能与服务的污染,保持服务的独立性和专业性。
3. 加速迭代周期- 拒绝一加功能排期一个月,追求快速迭代,适应互联网的快速变化。
架构目标
1. 高可用性- 架构出高可用性的应用服务,确保系统的稳定性和可靠性。
2. 易于迭代- 符合互联网高速迭代的需求,快速响应市场变化。
3. 服务的物料化、组装化、可编排- 通过物料化、组装化、可编排的服务,提高开发效率和人效。
实施策略
- 采用DDD的设计方法和过程,指导团队完成微服务的设计和开发。- 确保团队对DDD设计思想有深入理解和实践能力。
系统架构层级概述
应用层 (Application Layer)
应用服务- 应用服务位于应用层,主要负责表述应用和用户行为。- 负责服务的组合、编排和转发,处理业务用例的执行顺序以及结果的拼装。
领域事件服务- 包括领域事件的发布和订阅。- 通过事件总线和消息队列实现异步数据传输,实现微服务之间的解耦。
领域层 (Domain Layer)
领域服务- 领域服务封装了核心的业务逻辑。- 对同一个实体的一个或多个方法进行组合和封装,或对多个不同实体的操作进行组合或编排。
实体与值对象- 实体自身的行为在实体类内部实现,向上封装成领域服务暴露。
聚合解耦- 原则上禁止跨聚合的领域服务调用和跨聚合的数据相互关联。
基础层 (Infrastructure Layer)
基础服务- 为各层提供资源服务,如数据库、缓存等。- 通过依赖反转的方式为各层提供基础资源服务。
仓储服务- 领域服务和应用服务调用仓储服务接口,实现数据的持久化或直接访问基础资源。
接口层 (Interface Layer)
接口服务- 处理用户发送的Restful请求和解析用户输入的配置文件等。- 将信息传递给应用层。
开发环境配置
- JDK 1.8 - JDK 1.7 以下版本只能部分支持 Netty。
- Spring Boot 2.0.6.RELEASE
- 开发工具 - IntelliJ IDEA - Maven
代码示例(此处应提供代码示例,但根据要求不具体展示)
itstack-demo-ddd-01
└── src
├── main
│ ├── java
│ │ └── org.itstack.demo
│ │ ├── application
│ │ │├── event
│ │ ││ └── ApplicationRunner.java
│ │ │└── service
│ │ │ └── UserService.java
│ │ ├── domain
│ │ │├── model
│ │ ││ ├── aggregates
│ │ ││ │ └── UserRichInfo.java
│ │ ││ └── vo
│ │ ││ ├── UserInfo.java
│ │ ││ └── UserSchool.java
│ │ │├── repository
│ │ ││ └── IuserRepository.java
│ │ │└── service
│ │ │ └── UserServiceImpl.java
│ │ ├── infrastructure
│ │ │├── dao
│ │ ││ ├── impl
│ │ ││ │ └── UserDaoImpl.java
│ │ ││ └── UserDao.java
│ │ │├── po
│ │ ││ └── UserEntity.java
│ │ │├── repository
│ │ ││ ├── mysql
│ │ ││ │ └── UserMysqlRepository.java
│ │ ││ ├── redis
│ │ ││ │ └── UserRedisRepository.java
│ │ ││ └── UserRepository.java
│ │ │└── util
│ │ │ └── RdisUtil.java
│ │ ├── interfaces
│ │ │├── dto
│ │ ││└── UserInfoDto.java
│ │ │└── facade
│ │ │└── DDDController.java
│ │ └── DDDApplication.java
│ ├── resources
│ │ └── application.yml
│ └── webapp
│ └── WEB-INF
│ └── index.jsp
└── test
└── java
└── org.itstack.demo.test
└── ApiTest.java
<ul id="code_id_0"><li>1.</li><li>2.</li><li>3.</li><li>4.</li><li>5.</li><li>6.</li><li>7.</li><li>8.</li><li>9.</li><li>10.</li><li>11.</li><li>12.</li><li>13.</li><li>14.</li><li>15.</li><li>16.</li><li>17.</li><li>18.</li><li>19.</li><li>20.</li><li>21.</li><li>22.</li><li>23.</li><li>24.</li><li>25.</li><li>26.</li><li>27.</li><li>28.</li><li>29.</li><li>30.</li><li>31.</li><li>32.</li><li>33.</li><li>34.</li><li>35.</li><li>36.</li><li>37.</li><li>38.</li><li>39.</li><li>40.</li><li>41.</li><li>42.</li><li>43.</li><li>44.</li><li>45.</li><li>46.</li><li>47.</li><li>48.</li><li>49.</li><li>50.</li><li>51.</li></ul>
演示部分重点代码块,完整代码下载关注公众号;bugstack虫洞栈 | 回复DDD落地
application/UserService.java | 应用层用户服务,领域层服务做具体实现
/**
* 应用层用户服务
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
public interface UserService {
UserRichInfo queryUserInfoById(Long id);
}
<ul id="code_id_1"><li>1.</li><li>2.</li><li>3.</li><li>4.</li><li>5.</li><li>6.</li><li>7.</li><li>8.</li><li>9.</li><li>10.</li><li>11.</li></ul>
domain/repository/IuserRepository.java | 领域层资源库,由基础层实现
/**
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
public interface IUserRepository {
void save(UserEntity userEntity);
UserEntity query(Long id);
}
<ul id="code_id_2"><li>1.</li><li>2.</li><li>3.</li><li>4.</li><li>5.</li><li>6.</li><li>7.</li><li>8.</li><li>9.</li><li>10.</li><li>11.</li><li>12.</li></ul>
domain/service/UserServiceImpl.java | 应用层实现类,应用层是很薄的一层可以只做服务编排
/**
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
@Service("userService")
public class UserServiceImpl implements UserService {
@Resource(name = "userRepository")
private IUserRepository userRepository;
@Override
public UserRichInfo queryUserInfoById(Long id) {
// 查询资源库
UserEntity userEntity = userRepository.query(id);
UserInfo userInfo = new UserInfo();
userInfo.setName(userEntity.getName());
// TODO 查询学校信息,外部接口
UserSchool userSchool_01 = new UserSchool();
userSchool_01.setSchoolName("振华高级实验中学");
UserSchool userSchool_02 = new UserSchool();
userSchool_02.setSchoolName("东北电力大学");
List<UserSchool> userSchoolList = new ArrayList<>();
userSchoolList.add(userSchool_01);
userSchoolList.add(userSchool_02);
UserRichInfo userRichInfo = new UserRichInfo();
userRichInfo.setUserInfo(userInfo);
userRichInfo.setUserSchoolList(userSchoolList);
return userRichInfo;
}
}
<ul id="code_id_3"><li>1.</li><li>2.</li><li>3.</li><li>4.</li><li>5.</li><li>6.</li><li>7.</li><li>8.</li><li>9.</li><li>10.</li><li>11.</li><li>12.</li><li>13.</li><li>14.</li><li>15.</li><li>16.</li><li>17.</li><li>18.</li><li>19.</li><li>20.</li><li>21.</li><li>22.</li><li>23.</li><li>24.</li><li>25.</li><li>26.</li><li>27.</li><li>28.</li><li>29.</li><li>30.</li><li>31.</li><li>32.</li><li>33.</li><li>34.</li><li>35.</li><li>36.</li><li>37.</li><li>38.</li><li>39.</li></ul>
infrastructure/po/UserEntity.java | 数据库对象类
/**
* 数据库实体对象;用户实体
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
public class UserEntity {
private Long id;
private String name;
get/set ...
}
<ul id="code_id_4"><li>1.</li><li>2.</li><li>3.</li><li>4.</li><li>5.</li><li>6.</li><li>7.</li><li>8.</li><li>9.</li><li>10.</li><li>11.</li><li>12.</li><li>13.</li></ul>
infrastructrue/repository/UserRepository.java | 领域层定义接口,基础层资源库实现
/**
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
@Repository("userRepository")
public class UserRepository implements IUserRepository {
@Resource(name = "userMysqlRepository")
private IUserRepository userMysqlRepository;
@Resource(name = "userRedisRepository")
private IUserRepository userRedisRepository;
@Override
public void save(UserEntity userEntity) {
//保存到DB
userMysqlRepository.save(userEntity);
//保存到Redis
userRedisRepository.save(userEntity);
}
@Override
public UserEntity query(Long id) {
UserEntity userEntityRedis = userRedisRepository.query(id);
if (null != userEntityRedis) return userEntityRedis;
UserEntity userEntityMysql = userMysqlRepository.query(id);
if (null != userEntityMysql){
//保存到Redis
userRedisRepository.save(userEntityMysql);
return userEntityMysql;
}
// 查询为NULL
return null;
}
}
<ul id="code_id_5"><li>1.</li><li>2.</li><li>3.</li><li>4.</li><li>5.</li><li>6.</li><li>7.</li><li>8.</li><li>9.</li><li>10.</li><li>11.</li><li>12.</li><li>13.</li><li>14.</li><li>15.</li><li>16.</li><li>17.</li><li>18.</li><li>19.</li><li>20.</li><li>21.</li><li>22.</li><li>23.</li><li>24.</li><li>25.</li><li>26.</li><li>27.</li><li>28.</li><li>29.</li><li>30.</li><li>31.</li><li>32.</li><li>33.</li><li>34.</li><li>35.</li><li>36.</li><li>37.</li><li>38.</li><li>39.</li><li>40.</li><li>41.</li></ul>
interfaces/dto/UserInfoDto.java | DTO对象类,隔离数据库类
/**
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
public class UserInfoDto {
private Long id; // ID
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
<ul id="code_id_6"><li>1.</li><li>2.</li><li>3.</li><li>4.</li><li>5.</li><li>6.</li><li>7.</li><li>8.</li><li>9.</li><li>10.</li><li>11.</li><li>12.</li><li>13.</li><li>14.</li><li>15.</li><li>16.</li><li>17.</li><li>18.</li></ul>
interfaces/facade/DDDController.java | 门面接口
/**
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
@Controller
public class DDDController {
@Resource(name = "userService")
private UserService userService;
@RequestMapping("/index")
public String index(Model model) {
return "index";
}
@RequestMapping("/api/user/queryUserInfo")
@ResponseBody
public ResponseEntity queryUserInfo(@RequestBody UserInfoDto request) {
return new ResponseEntity<>(userService.queryUserInfoById(request.getId()), HttpStatus.OK);
}
}
<ul id="code_id_7"><li>1.</li><li>2.</li><li>3.</li><li>4.</li><li>5.</li><li>6.</li><li>7.</li><li>8.</li><li>9.</li><li>10.</li><li>11.</li><li>12.</li><li>13.</li><li>14.</li><li>15.</li><li>16.</li><li>17.</li><li>18.</li><li>19.</li><li>20.</li><li>21.</li><li>22.</li><li>23.</li></ul>
- 原文作者:知识铺
- 原文链接:https://index.zshipu.com/geek001/post/20240730/DDD%E4%B8%93%E9%A2%98%E6%A1%88%E4%BE%8B%E4%B8%80%E5%88%9D%E8%AF%86%E9%A2%86%E5%9F%9F%E9%A9%B1%E5%8A%A8%E8%AE%BE%E8%AE%A1DDD%E8%90%BD%E5%9C%B0_51CTO%E5%8D%9A%E5%AE%A2_ddd%E9%A2%86%E5%9F%9F%E9%A9%B1%E5%8A%A8%E8%AE%BE%E8%AE%A1%E6%A1%88%E4%BE%8B--%E7%9F%A5%E8%AF%86%E9%93%BA/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com