解构领域驱动设计(二):领域驱动设计的核心之分层架构

反映业务规则的代码是整个软件的核心,但是它一般只占很小的一部分,在传统的基于贫血模型的分层软件架构中,业务规则可能分散到各个层、各个代码段,从而使得通过代码来还原业务规则或者保证代码与业务规则一致将变得非常困难。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<DesignerOrder> {
 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<DesignerOrder> selectBySpecification(DesignerOrder example) {
31         List<DesignerOrder> 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 结论

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

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

?

原文地址:https://www.cnblogs.com/baihmpgy/p/10259297.html

时间: 2024-10-19 21:02:29

解构领域驱动设计(二):领域驱动设计的核心之分层架构的相关文章

软件架构设计学习总结(22):软件架构——分层架构、事件驱动架构、微内核架构、微服务架构、基于空间的架构

分层架构 (Layered Architecture) 分层架构是最常见的架构,也被称为n层架构.多年以来,许多企业和公司都在他们的项目中使用这种架构,它已经几乎成为事实标准,因此被大多数架构师.开发者和软件设计者所熟知.比如MVC. 分层架构的一个特性就是 关注分离(separation of concerns) .在层中的组件只负责本层的逻辑.组件的划分很容易让它们实现自己的角色和职责,也比较容易地开发,测试管理和维护. 我们需要这样的冗余,即使业务层没有处理业务规则,也要通过业务层来调用数

RISC处理器设计(二)------指令集的设计

定义指令字长为32位,并把寄存器堆扩展到32个通用32位寄存器.一套包含8个寄存器的寄存器堆,对于一个优化好的进程,足够安排所有的本地变量.采用寄存器窗技术可以提高系统的吞吐率.使CPI<1.一套32位寄存器阵列能够实现4个嵌套深度的进程. 1.指令格式的设计 指令可以分为四大类: 类别 说明 运算类 寄存器数据算术逻辑运算 访存类 主存储器访问(Load/Store) 跳转类 分支跳转(控制转移.条件与非条件) 特殊类 对诸如程序计数器PC等特殊寄存器操作的特殊指令 指令格式可以分为两大类:访

iOS分层架构设计

大家都知道,在移动设计开发中有很多种模式,最常用的单例设计模式.MVC设计模式.工厂设计模式.KVO.通知.代理等等.使用设计模式的目的:为了代码可重用性.让代码更容易被他人理解.保证代码可靠性.而架构设计是宏观的.全面的将设计魔术组织起来解决整个应用系统的方案.架构设计是人们对一个结构内的元素及元素间关系的一种主观映射的产物.一个好的架构设计有着良好的可复用性和可扩展性,这样可以满足用户不断变化的需求. 低耦合企业级系统架构设计 我们知道,软件设计的原则是提高软件系统的"可复用性"和

以属性为核心驱动的 全领域通用架构设计原理 (简称:属性架构原理)

以属性为核心驱动的全领域通用架构设计原理 (简称:属性架构原理) 联系方式:13547930387 Email:[email protected] 一.个人声明 我,参加工作也有5年多了,是一名普通的不能在普通的程序员,一直在使用公司自己的产品进行开发,因此技术比较菜,此设计完全是按照自己天真的想法而设计的,如果有不合理或很搞笑的地方,请轻拍,由衷的希望大家能提出宝贵的意见: 根据此设计原理我也做了一个简单的(demo)架构来支撑和验证此理论的可行性,由于技术功底不太好,有不合理之处请大家谅解,

领域驱动系列二策略模式的应用

一.简介 随着模型的不断扩大,发现模型中不单单只有"名词",还有许多"谓词",简言之,就是领域知识中,会参杂者许多的业务规则,他们和实体一样,都扮演者领域模型中的核心角色. 所以我们在建立领域模型的时候,不单单只关注实体和值对象,业务规则也被纳入到了领域模型中,如果业务规则变化不频繁,我们可以使用硬编码来解决,但是实际开发中业务规则的变化往往是变化的非常频繁的.当然你可以使用大量的If else来解决这个问题,但是这种代码是很难维护的.而且会影响原先的业务,所以这个

DDD领域驱动设计之领域服务

1.DDD领域驱动设计实践篇之如何提取模型 2.DDD领域驱动设计之聚合.实体.值对象 3.DDD领域驱动设计之领域基础设施层 什么是领域服务,DDD书中是说,有些类或者方法,放实体A也不好,放实体B也不好,因为很可能会涉及多个实体或者聚合的交互(也可能是多个相同类型的实体),此时就应该吧这些代码放到领域服务中,领域服务其实就跟传统三层的BLL很相似,只有方法没有属性,也就没有状态,而且最好是用动词命名,service为后缀,但是真正到了实践的时候,很多时候是很难区分是领域实体本身实现还是用领域

.NET领域驱动设计—看DDD是如何运用设计模式颠覆传统架构

阅读目录: 1.开篇介绍 2.简单了解缘由(本文的前期事宜) 3.DomainModel扩展性(运用设计模式设计模型变化点) 3.1.模型扩展性 3.2.设计模式的使用(苦心专研的设计模式.设计思想可以随意使用了) 3.3.部分类的使用(封装内部对象) 3.4.高强度的OO设计(面向特定领域的高度抽象设计形成特定领域框架) 4.DomainModel业务逻辑规则配置(将扩展点分离后使用适当的配置将规则IOC进去) 5.DDD简单总结(DDD是什么?它是"战术") 1]开篇介绍 这篇文章

领域驱动设计(一)理解分层架构

“企业级应用系统”具有复杂的业务,和相对较长的生命周期,在其生命周期中,业务规则将会是经常变化的,所使用的技术也可能发生变更.为了后期能更好的对这类系统进行扩展和维护,我们可以选择面向领域的多层架构,降低组件之间.层与层之间的耦合,这样在每次业务逻辑发生变化或者有新的业务扩展时,我们都能将变化锁定在领域层,从而最大限度的降低对其他层的影响. 领域驱动架构通常分为四层:表示层.应用层.领域层和基础设施层. 表示层(Presentation) 该层的主要职责是通过用户界面向用户显示数据信息,同时解释

领域驱动设计:分离领域

本章大部分内容摘自:<领域驱动设计:软件核心复杂性应对之道>一书中的第四章,分离领域,纯属原创.如有错误请指正,相互学习. 模式:LAYERED ARCHITECTURE (分层结构) 在面向对象的程序中,常常会在业务对象中直接写入用户界面.数据库访问等支持代码.而一些额外的业务逻辑则会被嵌入到用户界面组件和数据库脚本的行为中.这么做是为了以最简单的方式在短期内完成开发工作. 如果与领域有关的代码大量分散在大量的其他代码之中,那么查看和分析领域代码就会变得相当困难.对用户界面的简单修改实际上很