.NET:關於資料模型、領域模型和視圖模型的一些思考

來源:互聯網
上載者:User
文章目錄
  • 程式碼範例
  • 程式碼範例
背景

資料模型、領域模型和視圖模型是“模型”的三種角色,一些架構用一種類型表示這三種角色,如:傳統三層架構。也有一些架構用兩種類型表示這三種角色,如:結合ORM的領域驅動架構。非常少見的情境是用三種類型表示這三種角色,我只在個別領域這麼弄過,如:工作流程引擎。

今天只說一個話題:是否有必要為視圖模型引入獨立的類型?還是用一種類型表達領域模型和視圖模型這兩種角色比較方便?引入一些詞彙:

  • A方案:用一種類型表達領域模型和視圖模型這兩種角色,又叫公開領域模型到視圖(Open Domain To View)。
  • B方案:為視圖模型引入獨立的類型,又叫使用資料轉送對象(DTO)。
A方案

因為領域模型和視圖模型是一個類型,所以領域模型會從UI進行重建,因為領域模型會從UI進行重建,而UI層是不能相信的,所以必須對領域模型進行驗證(包含IsValid()方法),而且領域的很多方法都是修複領域模型的非法狀態,如:重新計算訂單總額、加密未加密的密碼屬性等等。

程式碼範例
 1     internal sealed class TestGridCommandHandler : ApplicationService, 2         ICommandHandler<CreateTestGrid>, 3         ICommandHandler<UpdateTestGrid>, 4         ICommandHandler<DeleteTestGrid> 5     { 6         public void Handle(CreateTestGrid command) 7         { 8             var testGridService = this.Service<TestGridService>(); 9 10             testGridService.Create(command.TestGridInfo);11             command.Id = command.TestGridInfo.Id;12         }13 14         public void Handle(UpdateTestGrid command)15         {16             var testGridService = this.Service<TestGridService>();17 18             testGridService.Update(command.TestGridInfo);19         }20 21         public void Handle(DeleteTestGrid command)22         {23             this.Service<TestGridService>().Delete(command.Id);24         }25     }

注意看第二個方法,這裡的command.TestGridInfo就是領域模型,從用戶端重建後直接調用ApplicationService進行update,update負責修複模型狀態、執行驗證和處理開放式並行存取。

B方案

因為領域模型和視圖模型是一個不同的類型,所以領域模型不會從UI進行重建,因為UI進行重建的只是視圖模型, 所以要從資料庫載入一份領域模型,然後將視圖模型合并到領域模型中,這裡的合并不是指用AutoMapper這樣的合并工具,而是一種合理的合并過程(不能用反射繞過領域模型封裝的邏輯),在這個合并過程,領域模型始終處於合法狀態(也可以不合法,很多人都這麼弄,保留IsValid()方法即可)。

程式碼範例
 1     internal sealed class TestOrderCommandHandler : ApplicationService, 2         ICommandHandler<CreateTestOrder>, 3         ICommandHandler<UpdateTestOrder>, 4         ICommandHandler<DeleteTestOrder> 5     { 6         public void Handle(CreateTestOrder command) 7         { 8             var testOrderService = this.Service<TestOrderService>(); 9 10             var testOrder = command.CreateTestOrder();11 12             testOrderService.Create(testOrder);13             command.Id = testOrder.Id;14         }15 16         public void Handle(UpdateTestOrder command)17         {18             var testOrderService = this.Service<TestOrderService>();19 20             var testOrder = testOrderService.Repository.Load(command.Id);21             testOrder.CheckOptimisticKey(command.TestOrderInfo.OptimisticKey);22             23             command.UpdateTestOrder(testOrder);24             testOrderService.Update(testOrder);25         }26 27         public void Handle(DeleteTestOrder command)28         {29             this.Service<TestOrderService>().Delete(command.Id);30         }31     }

注意看第二個方法,這裡先用Repository從資料庫返回一個領域模型,執行樂觀鎖檢查,用視圖模型修改領域模型(不是簡單的反射),然後調用ApplicationService進行Update。

備忘

只看代碼大家可能覺得A方案比較簡單,而B方案視乎有點脫褲子放屁的感覺,我之前都是用的A方案,開發效率確實高,但是應對比較複雜的邏輯就非常不爽了,具體為啥不爽我還沒有想明白。

我現在非常有信心用好任何一個方案,因為一個高人告訴我:關注代碼細節勝於關注這些架構上的問題。

結合四色原型,我覺得可以這樣弄:PPT和DES用A方案,MI用B方案。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.