解構領域驅動設計(二):分層架構

反映業務規則的代碼是整個軟件的核心,可是它通常只佔很小的一部分,在傳統的基於貧血模型的分層軟件架構中,業務規則可能分散到各個層、各個代碼段,從而使得經過代碼來還原業務規則或者保證代碼與業務規則一致將變得很是困難。DDD分層架構的核心思想就是將全部業務規則的代碼抽取到領域層,保證領域層的編碼與領域模型是徹底一致的。數據庫

下圖是DDD的分層架構。
緩存

 

必定要牢記:DDD分層架構一個核心任務,就是將軟件最重要的資產——業務規則分離出來,抽象在領域層,並確保這些代碼是領域模型的正確實現。關於領域模型的實現,在下一篇文章介紹。 架構


接下來,我將經過代碼來演示這個新的分層架構。app

1 應用層分佈式

應用層在這裏很是的簡單清晰,它僅僅是將基礎設施層、領域層提供的功能裝配起來完成任務,這一層的代碼邏輯很是簡單。ide

下面是建立設計師訂單的裝配任務。ui

 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 }

 

這裏例舉了建立訂單、付款、退款的應用層代碼。this

這裏,訂單建立有2個步驟:編碼

(1)使用Factory建立新的業務對象;spa

(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 結論

 

必定要牢記:DDD分層架構一個核心任務,就是將軟件最重要的資產——業務規則分離出來,抽象在領域層,確保這些代碼是領域模型的正確實現。 

 

經過以上的分層示例,咱們能夠總結出來領域驅動設計的代碼基本模式:

  1. 上層應用層經過Factory、Repository、領域對象協同來完成用戶任務。
  2. 經過Factory、Repository來處理領域對象生命週期管理,包括領域對象建立、加載、持久化。
  3. 領域對象由狀態和對狀態變動的操做組成,它是業務規則的實現。在這裏,字段表明狀態,方法表明狀態變動。領域對象狀態變動後,由Repository進行持久化。如何涉及多個領域對象狀態變動的一致性,則這幾個領域對象的狀態變動將組合在一塊兒,由Repository進行一致性變動。
  4. 基本模式:新建——經過Factory建立領域對象,調用領域對象方法更改狀態,使用Repository將領域對象持久化;變動——經過Repository加載領域對象,調用領域對象方法更改狀態,使用Repository將領域對象持久化。

相關文章
相關標籤/搜索