Su的技术博客

  • 首页
  • 原创
  • 视频
  • Java
  • MySQL
  • DDD
  • 事故复盘
  • 架构方案
  • AI
  • Other
  • 工具
    • AI工具集
    • 工具清单
    • JSON在线格式化
    • JSON在线比较
    • SQL在线格式化
  • 打赏
  • 关于
路很长,又很短
  1. 首页
  2. DDD
  3. 正文
                           

【转载】解构领域驱动设计(二):分层架构

2023-12-11 1678点热度 0人点赞 0条评论

反映业务规则的代码是整个软件的核心,但是它一般只占很小的一部分,在传统的基于贫血模型的分层软件架构中,业务规则可能分散到各个层、各个代码段,从而使得通过代码来还原业务规则或者保证代码与业务规则一致将变得非常困难。DDD分层架构的核心思想就是将所有业务规则的代码抽取到领域层,保证领域层的编码与领域模型是完全一致的。

下图是DDD的分层架构。
解构领域驱动设计(二):分层架构

一定要牢记:DDD分层架构一个核心任务,就是将软件最重要的资产——业务规则分离出来,抽象在领域层,并确保这些代码是领域模型的正确实现。关于领域模型的实现,在下一篇文章介绍。

接下来,我将通过代码来演示这个新的分层架构。

1 应用层

应用层在这里非常的简单清晰,它仅仅是将基础设施层、领域层提供的功能装配起来完成任务,这一层的代码逻辑非常简单。

下面是创建设计师订单的装配任务。

 1 @Service
 2 @Transactional(rollbackFor = Exception.class)
 3 public class DesignerOrderServiceImpl implements DesignerOrderService {
 4     @Autowired
 5     private DesignerOrderRepository designerOrderRepository;
 6     @Autowired
 7     private RefundOrderRepository refundOrderRepository;
 8 
 9     @Override
10     public DesignerOrder createOrder(int customerId, int designerId) {
11         DesignerOrder order = DesignerOrderFactory.createOrder(customerId, designerId);
12 
13         designerOrderRepository.create(order);
14 
15         return designerOrderRepository.selectByKey(order.getId());
16     }
17 
18     @Override
19     public void pay(int orderId, float amount) {
20         DesignerOrder order = designerOrderRepository.selectByKey(orderId);
21         if (order == null) {
22             AppException.throwAppException(AppExceptionMessage.DESIGNER_ORDER_NOT_EXIST_CODE, AppExceptionMessage.DESIGNER_ORDER_NOT_EXIST, orderId);
23         }
24 
25         order.pay(amount);
26         designerOrderRepository.update(order);
27     }
28 
29     @Override
30     public RefundOrder refund(int orderId, String cause) {
31         DesignerOrder order = designerOrderRepository.selectByKey(orderId);
32         if (order == null) {
33             AppException.throwAppException(AppExceptionMessage.DESIGNER_ORDER_NOT_EXIST_CODE, AppExceptionMessage.DESIGNER_ORDER_NOT_EXIST, orderId);
34         }
35 
36         RefundOrder refundOrder = order.refund(cause);
37 
38         designerOrderRepository.update(order);
39 
40         refundOrderRepository.create(refundOrder);
41 
42         return refundOrderRepository.selectByKey(refundOrder.getId());
43     }
44 }

这里例举了创建订单、付款、退款的应用层代码。

这里,订单创建有2个步骤:

(1)使用Factory创建新的业务对象;

(2)使用Repository将业务对象持久化到数据库。

付款3个步骤:

(1)使用Repository加载订单业务对象到内存;

(2)调用订单业务对象的付款方法更改业务对象状态;

(3)使用Repository将业务对象持久化到数据库。

退款有3个步骤:

(1)使用Repository加载订单业务对象到内存;

(2)调用设计师订单业务对象的退款方法改变业务对象的状态,然后生成一个退款订单业务对象;

(3)使用Repository持久化设计师订单和退款订单业务对象。

此外,应用层还额外处理了数据持久化的事务。

2 领域层

领域层是实现所有业务规则的领域对象,它是整个软件的核心,并且与领域模型保持一致。

 1 @Data
 2 @EqualsAndHashCode(of = {"id"})
 3 public class DesignerOrder implements Entity {
 4     private int id;
 5     private DesignerOrderState state;
 6     private int customerId;
 7     private int designerId;
 8     private float area;
 9 
10     private float expectedAmount;
11     private int estimatedDays;
12     private DesigningProgressReport progressReport;
13 
14     private String abortCause;
15 
16     private float actualPaidAmount;
17 
18     private int feedbackStar;
19     private String feedbackDescription;
20 
21     private Date createdTime;
22     private Date updatedTime;
23 
24     public void pay(float amount) {
25         Assert.isTrue(amount > 0, "The amount must be bigger than 0.");
26 
27         if (!DesignerOrderWorkflowService.canChangeState(state, DesignerOrderState.PAID)) {
28             DomainException.throwDomainException(DomainExceptionMessage.PAYMENT_NOT_IN_READY_STATE_CODE, DomainExceptionMessage.PAYMENT_NOT_IN_READY_STATE, this.id, this.state);
29         }
30 
31         if (Math.abs(amount - this.expectedAmount) > 0.01) {
32             DomainException.throwDomainException(DomainExceptionMessage.PAYMENT_NOT_MATCHED_CODE, DomainExceptionMessage.PAYMENT_NOT_MATCHED, this.id, this.expectedAmount, amount);
33         }
34 
35         this.state = DesignerOrderWorkflowService.changeState(this.id, state, DesignerOrderState.PAID);
36         this.actualPaidAmount = amount;
37 
38         // 付款完成后,自动启动进度跟踪
39         this.progressReport.startup();
40     }
41 
42     public RefundOrder refund(String cause) {
43         this.assertCanRefund();
44 
45         this.state = DesignerOrderWorkflowService.changeState(this.id, state, DesignerOrderState.REFUND);
46 
47         return RefundOrderFactory.newRefundOrder(this, cause);
48     }
49 
50     private void assertCanRefund() {
51         DesigningProgressNode constructionDrawingDesignNode = this.progressReport.getNode(DesigningProgressNodeType.CONSTRUCTION_DRAWING_DESIGN);
52         if (constructionDrawingDesignNode.getState() == DesigningProgressNodeState.REQUEST_COMPLETION ||
53                 constructionDrawingDesignNode.getState() == DesigningProgressNodeState.CONFIRM_COMPLETION) {
54             DomainException.throwDomainException(DomainExceptionMessage.FAILED_TO_REFUND_FOR_PROGRESS_CODE, DomainExceptionMessage.FAILED_TO_REFUND_FOR_PROGRESS, this.id);
55         }
56     }
57 
58     @Override
59     public boolean sameIdentityAs(DesignerOrder other) {
60         return this.equals(other);
61     }
62 }

你可以发现业务对象的代码有:

  • 业务对象内部状态,即它包含的属性(字段)。
  • 业务对象方法,即业务规则的实现,业务对象方法一般完成业务对象状态变更。
  • 业务对象关联,包含关联业务对象的属性或者字段。

关于领域层的编码模式,在下文会详细介绍。

3 基础设施层

基础设施层为上层提供通用的技术能力,包括消息传递、缓存、远程调用、分布式事务、持久化、UI绘制等。以下是持久化实现的一段代码。它以整个实体作为存储单元(注意:准确的说,是以聚合根为存储单元,后续详细介绍)。

 1 @Repository
 2 public class DesignerOrderRepositoryImpl implements DesignerOrderRepository {
 3     private static final String DESIGNER_ORDER_TABLE = "designer_order";
 4 
 5     @Autowired
 6     private DesignerOrderMapper designerOrderMapper;
 7 
 8     @Override
 9     public void create(DesignerOrder order) {
10         if (designerOrderMapper.create(order) == 0) {
11             TableException.throwTableException(DESIGNER_ORDER_TABLE, TableOperation.CREATE);
12         }
13     }
14 
15     @Override
16     public DesignerOrder selectByKey(int id) {
17         DesignerOrder order = designerOrderMapper.selectByKey(id);
18         buildConnection(order);
19         return order;
20     }
21 
22     @Override
23     public DesignerOrder selectOneBySpecification(DesignerOrder example) {
24         DesignerOrder designerOrder = designerOrderMapper.selectOneBySpecification(example);
25         buildConnection(designerOrder);
26         return designerOrder;
27     }
28 
29     @Override
30     public List selectBySpecification(DesignerOrder example) {
31         List designerOrders = designerOrderMapper.selectBySpecification(example);
32         buildConnection(designerOrders);
33         return designerOrders;
34     }
35 
36     @Override
37     public void update(DesignerOrder order) {
38         if (designerOrderMapper.update(order) == 0) {
39             TableException.throwTableException(DESIGNER_ORDER_TABLE, TableOperation.UPDATE);
40         }
41     }
42 }

4 结论

一定要牢记:DDD分层架构一个核心任务,就是将软件最重要的资产——业务规则分离出来,抽象在领域层,确保这些代码是领域模型的正确实现。

通过以上的分层示例,我们可以总结出来领域驱动设计的代码基本模式:

  1. 上层应用层通过Factory、Repository、领域对象协同来完成用户任务。
  2. 通过Factory、Repository来处理领域对象生命周期管理,包括领域对象创建、加载、持久化。
  3. 领域对象由状态和对状态变更的操作组成,它是业务规则的实现。在这里,字段代表状态,方法代表状态变更。领域对象状态变更后,由Repository进行持久化。如何涉及多个领域对象状态变更的一致性,则这几个领域对象的状态变更将组合在一起,由Repository进行一致性变更。
  4. 基本模式:新建——通过Factory创建领域对象,调用领域对象方法更改状态,使用Repository将领域对象持久化;变更——通过Repository加载领域对象,调用领域对象方法更改状态,使用Repository将领域对象持久化。

解构领域驱动设计(二):分层架构

本文仅供学习!所有权归属原作者。侵删!文章来源:作者 道法自然 https://www.cnblogs.com/baihmpgy/p/10259297.html

更多文章:

  1. 解构领域驱动设计(三):领域驱动设计
  2. 殷浩详解DDD 第三讲 - Repository模式
  3. 殷浩详解DDD 第四讲:领域层设计规范
  4. DDD系列第五讲:聊聊如何避免写流水账代码
  5. FSM-COLA无状态状态机
  6. 手把手教你实战TDD
  7. 设计模式在外卖营销业务中的实践
  8. 殷浩详解DDD系列 第一讲 - Domain Primitive
  9. 关于聚合根、领域事件的那点事——深入浅出理解DDD
  10. 殷浩详解DDD系列 第二讲 - 应用架构
标签: 转载 架构 ddd 领域驱动设计 分层架构 基础设施层 领域层
最后更新:2023-12-11

秋天0261

关注Java领域,后端开发、Netty、Zookeeper、Kafka、ES、分布式、微服务、架构等。分享技术干货,架构设计,实战经验等。

打赏 点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

广告
文章目录
  • 1 应用层
  • 2 领域层
  • 3 基础设施层
  • 4 结论
最新 热点 推荐
最新 热点 推荐
微服务架构:必懂的6大性能维度 Anthropic Code with Claude 开发者大会:开启 AI Agent 新时代 视频笔记-微服务架构P4:必懂5种设计模式 视频笔记:微服务架构P4 设计模式:每服务数据库、API 网关和事件驱动架构 干货 | 论Elasticsearch数据建模的重要性 马蜂窝消息总线——面向业务的消息服务设计 基于 MySQL Binlog 实现可配置的异构数据同步 视频笔记:Google发布Agent2Agent协议
视频笔记:微服务架构P4 设计模式:每服务数据库、API 网关和事件驱动架构干货 | 论Elasticsearch数据建模的重要性视频笔记-微服务架构P4:必懂5种设计模式Anthropic Code with Claude 开发者大会:开启 AI Agent 新时代微服务架构:必懂的6大性能维度
迄今为止最完整的DDD实践 【2024.1】仍然活跃的开源LLM 系统设计 | 多对多关系模型拆解案例 Redis的BigKey(大key)、HotKey(热key)又引发了线上事故 二级缓存架构极致提升系统性能 ParNew+CMS 实践案例 : HiveMetastore FullGC诊断优化 预测 2025 AI 2.软件架构预述(译)

CRUD (1) Event Sourcing (1) graphql (1) id (1) NoSQL (1) quarkus (1) rest (1) RocketMQ (2) Spring Boot (1) zk (1) zookeeper (1) 上下文 (1) 事务消息 (1) 二级缓存 (1) 值对象 (1) 关系数据库 (1) 分布式缓存 (1) 原子性 (1) 唯一ID (1) 商品 (1) 多对多 (1) 子域 (1) 字符集 (1) 客户端心跳 (1) 幂等 (2) 干货 (1) 并发 (1) 应用场景 (1) 应用架构图 (1) 康威定律 (2) 异步复制 (1) 微服务架构 (3) 总体方案 (1) 技术方案 (2) 技术架构 (2) 技术架构图 (1) 技能 (1) 持续集成 (1) 支撑域 (1) 故障恢复 (1) 数据架构图 (1) 方案选型 (1) 日记 (1) 服务发现 (1) 服务治理 (1) 服务注册 (2) 机房 (1) 核心域 (1) 泄漏 (1) 洋葱架构 (1) 消息队列 (5) 源码剖析 (1) 灰度发布 (1) 熔断 (1) 生态 (1) 画图工具 (1) 研发团队 (1) 线程 (2) 组织架构 (1) 缓存架构 (1) 编码 (1) 视频 (20) 读写分离 (1) 贵州 (1) 软件设计 (1) 迁移 (1) 通用域 (1) 集群化 (1) 雪花算法 (1) 顺序消息 (1)

推荐链接🔗
  • AI工具集
  • 工具箱🛠️

COPYRIGHT © 2014-2025 verysu.com . ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

粤ICP备15033072号-2