EntityFramework之領域驅動設計實踐【擴充閱讀】:服務(Services)

來源:互聯網
上載者:User
服務(Services)

從本講開始,所涉及的DDD話題可能與EntityFramework關係不大了。網友千萬別罵我是標題黨,呵呵。由於這部分內容並非是特定於EntityFramework的,更多的是在介紹模式及實踐心得,所以EntityFramework的內容就會偏少了。為了使得針對一些話題的討論能夠延續下去,我仍然將這些文章安排在本系列中,希望讀者朋友能夠諒解。我也在標題中標註了【擴充閱讀】,表示所討論的內容已經不僅僅局限於EntityFramework了。

為了表示補償,透露一下EntityFramework 4.0的最新特性:EF CTP 4.0在“代碼優先”開發模式以及提升開發生產率方面做了重要改進。EF CTP 4.0引入了兩種新的類型:DbContext和DbSet。DbContext是ObjectContext的簡化版。詳情請見http://www.infoq.com/news/2010/07/EF-CTP-4。

言歸正傳,本文將對DDD中的又一重要角色:服務(Services)做一些簡單的介紹。提起服務,很多朋友都會想到“SOA”。而在領域驅動設計裡,服務貫穿於整個系統的各個層面。根據應用系統的領域驅動分層思想,服務被歸類為:應用程式層服務、領網域服務以及基礎結構層服務。應用程式層服務為表現層提供介面,根據DDD的思想,應用程式層很薄,不承擔任何商務邏輯的處理,僅僅是起到coordination的作用。因此,應用程式層服務也不會牽涉到商務邏輯。在CQRS模式中,Command Service以及Query Service就是應用程式層服務。基礎結構層服務是顯而易見的,比如,郵件發送服務、資料服務、事件匯流排等等。這些服務是與領域無關的,只跟技術實現相關。假想這樣一個例子:將貨物從倉庫A轉移到倉庫B,如果轉倉成功,則向倉庫管理員及操作員發送SMS。這是倉儲管理領域常見的業務需求,經典的寫法類似如下:

  1: public class TransferService : IDomainService
  2: {
  3:     public void Transfer(Warehouse a, 
  4:                          Warehouse b, 
  5:                          Item item, Qty qty)
  6:     {
  7:         using (IRepositoryTransactionContext ctx = Ioc.GetService<IRepositoryTransactionContext>())
  8:         {
  9:             Inventory oItemInA = a.GetInventory(item);
 10:             if (oItemInA.Qty < qty)
 11:             {
 12:                 // raise not enough inventory event or exception
 13:                 throw new Exception();
 14:             }
 15:             Inventory oItemInB = b.GetInventory(item);
 16:             if (oItemInB == null)
 17:                 oItemInB = b.CreateInventory(item);
 18:             oItemInA.Qty -= qty;
 19:             oItemInB.Qty += qty;
 20:             ctx.SaveChanges();
 21:         }
 22:     }
 23: }
 24: 

在上面的虛擬碼中,我們已經看到了領網域服務(Domain Service)的影子。在DDD裡,領網域服務用以處理那種“放在哪裡都不合適”的商務邏輯。比如上面的轉倉業務,從物件導向的角度看,既不是倉庫應有的操作,也不是貨物(Item)的行為。為了明確領域對象的職責,DDD將這樣的商務邏輯“抽”出來,置於領網域服務當中。對於發送SMS的需求,就需要由應用程式層服務通過“協調”進行處理了。比如:在調用了領網域服務並獲得響應以後,根據響應結果以及外部配置資訊,進而調用基礎結構層服務(SMSService)實現SMS的發送。

看到這裡你會發現,其實哪些業務應該放在實體中,哪些需要使用服務來處理,並沒有一個絕對的標準。還是那句老話:憑經驗。你還會發現,如果從實體將商務邏輯全部“抽”到服務裡,實體將成為僅包含getter/setter的對象,於是貧血模型產生了。正因為DDD提倡面向領域,並將通用語言和領域模型擺在很重要的位置,因此,DDD是不主張貧血模型的。

個人認為,領網域服務的引入,增加了模型的抗需求變更的能力。我們可以通過需求分析,找出商務邏輯中易變的部分,以領網域服務的方式“注入”到領域模型中,今後若有需求變更,則可以無需更改任何現有組件,完成業務處理邏輯的改變。[TBD: 這樣的想法還有待進一步證實]

有關領網域服務的內容,本文暫且討論這些。讀者朋友可以在實踐中提出問題,然後在此與大家分享討論。本文還引出了一個話題,就是應用程式層服務的協調問題。比如,本文的例子中,是在應用程式層服務中調用SMSService實現SMS發送,如果直接將這部分內容寫在應用程式層服務中,勢必降低系統的擴充性。比如,今後希望不僅要發送SMS,而且還要發送Email。DDD的解決方案是引入事件模型。在完成轉倉操作時,向事件匯流排(Event Bus)發送事件,由事件訂閱者Subscriber捕獲並處理(Handle)事件。於是,今後我們只需要實現一個“WarehouseTransferSendEmailEventHandler”的事件處理器,並在Handle Event的調用中,向相關人員發送Email即可。NServiceBus就是一款經典的基於.NET的企業級應用通訊的架構,在基於事件的DDD架構中,NServiceBus發揮了重要作用。

從下一講開始,我將著重討論領域事件以及Event Sourcing,並對DDD的CQRS模式作個引子。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.