數據模型、領域模型和視圖模型是「模型」的三種角色,一些架構用一種類型表示這三種角色,如:傳統三層架構。也有一些架構用兩種類型表示這三種角色,如:結合ORM的領域驅動架構。很是少見的場景是用三種類型表示這三種角色,我只在個別領域這麼弄過,如:工做流引擎。數據庫
今天只說一個話題:是否有必要爲視圖模型引入獨立的類型?仍是用一種類型表達領域模型和視圖模型這兩種角色比較方便?引入一些詞彙:架構
由於領域模型和視圖模型是一個類型,因此領域模型會從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負責修復模型狀態、執行驗證和處理樂觀併發。app
由於領域模型和視圖模型是一個不一樣的類型,因此領域模型不會從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。this
只看代碼你們可能以爲A方案比較簡單,而B方案視乎有點脫褲子放屁的感受,我以前都是用的A方案,開發效率確實高,可是應對比較複雜的邏輯就很是不爽了,具體爲啥不爽我尚未想明白。加密
我如今很是有信心用好任何一個方案,由於一個高人告訴我:關注代碼細節勝於關注這些架構上的問題。spa
結合四色原型,我以爲能夠這樣弄:PPT和DES用A方案,MI用B方案。code