1. 程式人生 > 程式設計 >領域驅動設計DDD之領域服務

領域驅動設計DDD之領域服務

什麼是領域服務?

在戰術建模當中,並非所有模型都是事物。有些模型是對領域中的一些行為操作進行建模。此類模型我們稱之為領域服務。當一些重要的領域操作無法放到實體、值物件或者聚合時,他們本質是行為而不是事物。如果我們不尋找一些物件來封裝這些領域行為的話,又會演變成之前過程式的程式設計方式。我們希望在領域設計當中統一用模型物件進行互動。此時領域服務使用細粒度的領域物件如實體或者值物件進行互動,在服務內部描述領域知識得出結果並將其返回。

領域服務的引數和返回型別應該是領域物件。

三個特徵:
  • 它是與領域相關的操作如執行一個顯著的業務操作過程,但它又並不適合放入實體與值物件中。
  • 操作是無狀態的。
  • 對領域物件進行轉換,或以多個領域物件作為輸入進行計算,結果產生一個值物件。

總結: 當領域中的某個重要的過程或者轉換操作不是實體和值物件的自然職責時,應該在模型中新增一個作為獨立介面的操作,並將其宣告為領域服務。定義介面時要使用模式語言,並確保操作名稱是業務統一通用語言的術語。除此之外領域服務要成為無狀態的。

我們需要把握一個度,如果將所有領域知識都封裝到實體當中去時,模型就會因為行為過多導致充血,充血情況下很多實體的行為都是勉強且不自然的。而讓我們將行為一股腦的封裝到領域服務當中去的話,此時模型就因毫無行為導致貧血,我們又回到了傳統開發模式了。

區分不同的服務

在傳統的開發中我們已經有Service服務的概念了,這時候再引入領域服務時,我們可能就會開始混淆。在領域驅動設計中我們主要將服務分為三類,一類是應用服務,一類是領域服務,一類是基礎服務。如何去區分這三種服務呢?我的一個簡單的理解是通過服務自身所服務的客戶端來進行區分。應用服務提供面向使用者的服務,它所完成的是一整個使用者需求。領域服務提供面向應用層的服務,它所完成的是封裝領域知識,供應用層使用。基礎服務提供面向應用層和領域層的服務,它所提供的是專案中各個層都可能使用到的通用功能。

我們舉一個銀行轉賬的例子,通過不同服務所處理的事情來說明

  • 應用服務:獲取輸入,傳送訊息給領域層,監聽確認訊息,決定使用基礎服務來傳送郵件。
  • 領域服務:協調賬戶模型和總賬模型進行互動,執行相應的領域行為。
  • 基礎服務:按照應用服務的指示傳送郵件。

粒度

應用層負責對領域物件的行為進行協調,來滿足某一個領域需求。但如果領域物件都是實體和值物件等細粒度的物件時,應用層就得去了解這些細粒度的物件如何互動才能滿足領域需求。那此時便將領域內的知識洩露到應用層了。我們應該儘量避免領域知識洩露到應用層當中去。那此時領域服務就不失為一種良好的處理方式,通過將細粒度的領域物件封裝到領域服務當中去,將領域知識限制在領域服務當中,形成粗粒度的領域物件。因此應用層呼叫粗粒度的領域服務時也就無需關心其中複雜的物件互動。

轉換過程

我們舉一個商鋪系統中需要統計每日臺賬的功能,而這個功能我們放置到臺賬統計服務當中去。我們通過傳入一個商鋪實體以及日期,在方法內使用Repository資源庫(同DAO),進行獲取領域模型,再利用領域模型間的互動來完成臺賬的統計,最後封裝成一個臺賬模型返回出去。

public class LedgerAccountor {

    public LedgerSumary ledgerSumary(Shop aShop,Date date){
        int totalIncome = 0;
        int totalExpense = 0;
        
        List<ShopTrade> trades = ShopTradeRepository.getShopTrades(ashop,date);
        
        for(ShopTrade trade : trades){
            
            totalIncome += trade.getIncome();
            totalExpense += trade.getExpense();
            
        }
        
        return new LedgerSumary(totalIncome,totalExpense);
        
    }
    
}


複製程式碼
關於DDD的理解各有不同,歡迎網友評論一起探討。

轉自我的個人部落格 vc2x.com