领域驱动设计(DDD)概述

领域驱动设计(Domain-Driven Design,简称DDD)是一种以领域为中心的软件开发方法论。它由Eric Evans提出,旨在解决软件系统规模扩大带来的复杂性问题。DDD的核心在于通过建模来理解和表达业务领域知识,从而设计出高内聚、低耦合、具有良好扩展性的软件架构。

DDD的起源与发展

DDD的历史可以追溯到20世纪90年代,但随着微服务架构的兴起,DDD再次成为软件开发领域的热点。微服务架构强调服务的独立性和自治性,与DDD的理念不谋而合。

DDD的核心概念

  • 通用语言(Ubiquitous Language):开发团队与领域专家共同使用的语言,以确保对业务概念的一致理解。
  • 子领域划分:将业务领域划分为核心子域、通用子域和支撑子域,以识别关键业务价值和功能。
  • 领域模型:基于领域知识的抽象,用于指导软件设计和开发。

DDD实战落地策略

本专题将通过分章节的方式,设计不同的架构模型,并结合实战案例,帮助读者深入理解DDD的应用。学习DDD并将其应用于实际项目,是快速提升应用级开发能力的途径。

结语

通过DDD,我们能够构建出更加符合业务需求的软件系统。Hi HelloWorld!我们正站在应用级开发的新起点。
DDD专题案例一《初识领域驱动设计DDD落地》_应用层

微服务设计与开发目标

领域驱动设计(DDD)应用

依靠领域驱动设计的设计思想,我们致力于通过事件风暴建立领域模型,合理划分领域逻辑和物理边界。以下是我们的设计和开发策略:

1. 领域模型构建- 利用事件风暴方法,建立清晰的领域模型。- 确保领域逻辑与物理边界的合理划分。

2. 领域对象和服务矩阵- 定义领域对象,明确其职责和行为。- 构建服务矩阵,关联领域对象与服务。

3. 服务架构图- 绘制服务架构图,展示各服务间的关系和交互。

4. DDD分层架构- 遵循DDD分层架构思想,定义代码结构模型。- 保证业务模型与代码模型的一致性。

开发原则

1. 避免单体应用- 拒绝泥球小单体,确保系统的模块化和可维护性。

2. 功能与服务分离- 拒绝功能与服务的污染,保持服务的独立性和专业性。

3. 加速迭代周期- 拒绝一加功能排期一个月,追求快速迭代,适应互联网的快速变化。

架构目标

1. 高可用性- 架构出高可用性的应用服务,确保系统的稳定性和可靠性。

2. 易于迭代- 符合互联网高速迭代的需求,快速响应市场变化。

3. 服务的物料化、组装化、可编排- 通过物料化、组装化、可编排的服务,提高开发效率和人效。

实施策略

  • 采用DDD的设计方法和过程,指导团队完成微服务的设计和开发。- 确保团队对DDD设计思想有深入理解和实践能力。

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

系统架构层级概述

应用层 (Application Layer)

应用服务- 应用服务位于应用层,主要负责表述应用和用户行为。- 负责服务的组合、编排和转发,处理业务用例的执行顺序以及结果的拼装。

领域事件服务- 包括领域事件的发布和订阅。- 通过事件总线和消息队列实现异步数据传输,实现微服务之间的解耦。

领域层 (Domain Layer)

领域服务- 领域服务封装了核心的业务逻辑。- 对同一个实体的一个或多个方法进行组合和封装,或对多个不同实体的操作进行组合或编排。

实体与值对象- 实体自身的行为在实体类内部实现,向上封装成领域服务暴露。

聚合解耦- 原则上禁止跨聚合的领域服务调用和跨聚合的数据相互关联。

基础层 (Infrastructure Layer)

基础服务- 为各层提供资源服务,如数据库、缓存等。- 通过依赖反转的方式为各层提供基础资源服务。

仓储服务- 领域服务和应用服务调用仓储服务接口,实现数据的持久化或直接访问基础资源。

接口层 (Interface Layer)

接口服务- 处理用户发送的Restful请求和解析用户输入的配置文件等。- 将信息传递给应用层。

开发环境配置

  1. JDK 1.8 - JDK 1.7 以下版本只能部分支持 Netty。
  2. Spring Boot 2.0.6.RELEASE
  3. 开发工具 - 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&lt;UserSchool&gt; userSchoolList = new ArrayList&lt;&gt;();
        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&lt;&gt;(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>

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