反映业务规则的代码是整个软件的核心,但是它一般只占很小的一部分,在传统的基于贫血模型的分层软件架构中,业务规则可能分散到各个层、各个代码段,从而使得通过代码来还原业务规则或者保证代码与业务规则一致将变得非常困难。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 结论
通过以上的分层示例,我们可以总结出来领域驱动设计的代码基本模式: