簡體   English   中英

了解域實體中的域服務與應用程序服務與行為(方法)

[英]Understanding Domain Services vs. Application Services vs. Behavior (Methods) in Domain Entities

我們一直致力於為分層應用程序開發架構。 我們計划建立一個ASP.NET MVC表示層,同時為移動瀏覽器和“普通”瀏覽器提供服務。 也就是說,如果用戶在移動設備上導航到該站點,我們需要相同的ASP.NET MVC表示層來提供針對移動瀏覽器優化的視圖,同時提供針對經過優化的“常規”視圖桌面/筆記本電腦瀏覽器,如果用戶使用他們的台式機/筆記本電腦 目前,我們還沒有計划支持原生移動應用,但我們可能會在未來添加該功能。 此外,該體系結構將具有域模型的層 - 域實體,域服務等,應用程序服務和使用EF代碼優先POCO以及存儲庫和工作單元模式的數據層 - 所有標准域模型類型設計。

但是,我一直試圖弄清楚域實體中的域服務,應用程序服務和行為(方法)之間的區別,因為它適用於我們正在開發的系統。 以下是我們的系統中的高級用例。

我們有Reports和ReportGroups。 這兩個實體之間存在多對多關系。 數據庫表是:Reports < - > Jct_Reports_ReportGroups < - > ReportGroups,域實體看起來像:

Report class :
    public string ReportName { get; set; }
    ...
    public virtual ICollection<ReportGroup> ReportGroups { get; set; }

ReportGroup class :
    public string GroupName { get; set; }
    ...
    public virtual ICollection<Report> Reports { get; set; }

當然,用戶可以創建報告(無需創建報告組),他們可以創建包含一個或多個報告的報告組。 此外,用戶可以刪除報告。 當發生這種情況時,會發生許多事情。 首先,我們檢查報告是否在任何報告組中(單個報告可以在許多不同的報告組中)。 如果在任何報告組中找到報告,我們將遍歷每個報告組並從報告組中刪除報告(通過刪除Jct_Reports_ReportGroups表中的一行)。 然后,對於包含要刪除的報告的每個報告組,我們會檢查報告組中是否還有其他報告。 如果報告組中沒有其他報告,我們還會刪除報告組(通過刪除ReportGroups表中的行)。 如果報告組中還有其他報告,我們不會刪除報告組。 如果所有這些操作都成功,我們將刪除用戶選擇的要刪除的報告(通過刪除Reports表中的行)。 最后,向用戶顯示一條消息,指出報告刪除是否成功。

我希望這是一個足夠的用例來幫助理解我們的整體應用程序中的一小部分。

我在某處讀過域服務封裝了自然不適合域對象的業務邏輯,並且不是典型的CRUD操作,而外部消費者使用應用程序服務與您的系統通信 - 如果消費者需要訪問CRUD操作,他們會暴露在這里。 但是,我只是不了解POCO域實體中將采用哪些方法(業務邏輯),哪些業務邏輯將被視為域服務並包含在業務層中,以及哪些業務邏輯將被視為包含在應用服務層。 所以,我的主要問題是:鑒於上面的用例,關於如何在域實體中突破域服務與應用服務與行為(方法)的建議是什么?

這是一個很有問題的問題。

我更喜歡以下非嚴格的指導方針:

應用程序服務 :想象一下,我們有一組用例描述用戶與系統的交互。 假設我們有LoginCash transfer案例,具有特定的輸入和輸出; 他們還描述了成功和失敗的情景。 有了這個,我們通常都有一個應用程序服務規范:我公開了LoginResul Login(name, pass)TransferResult CashTrasnfer(from, to, amount)方法,在out和out中都有或多或少相同的成功/失敗行為。

很明顯,為了實現用例,應用程序服務調用BL(但增加了安全性和其他特定於應用程序的檢查)。

域服務 :正如您所描述的:'自然不適合域對象'。

擁有CashTrasnfer用例,我們必須:

  • 加載帳戶'從'
  • 加載帳戶'到'
  • 檢查'來自'余額'//可能會返回錯誤
  • 驗證帳戶訪問權限(鎖定等)//可能會返回錯誤
  • 從“從”中提取“金額”
  • 把金額加到'到'
  • (理想情況下,這應該是單一的“商業”交易)。

很明顯,這個函數不適合Account實體 - 所以最好有一個特殊的TransferService


特別是關於Report / ReportGroup功能 - 它可以是實體范圍,因為沒有非邏輯引用(所有項都可以從報告中訪問):

Report.Remove() {
    foreach(group in Groups) {
        group.RemoveReport(this);
    }
    repository.Remove(this);
} 
Group.RemoveReport(report) {
    reports.Remove(report);
    if(reports.Count == 0)
        repository.Remove(this);
}

或者在報表服務和實體之間拆分(引用存儲庫可能會有問題):

Report.RemoveFromAllGroups() {
   foreach(group in Groups) {
        group.RemoveReport(this);
        if(group.IsEmpty)
            //add to collection to return
    }
}
Service.Remove(report) 
{
    var emptyGroups = report.RemoveFromAllGroups();
    reportRepo.Remove(report);
    groupRepo.Remove(emptyGroups);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM