系統開發最難的是職責的合理分配,或者叫:「如何合理的組織代碼」,今天說一個關於這方面問題的示例,但願你們多批評。數據庫
項目總體採用簡單的CQRS架構,Command端採用DDD組織,Query直接從數據庫返回dynamic類型。Event能夠用來處理跨聚合通訊,也能夠用來處理長事務或離線事務。架構
採用狀態模式處理狀態遷移。app
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace Happy.Example.Domain.TestOrders 8 { 9 public interface ITestOrderState 10 { 11 void AddTestOrderDetail(TestOrderDetail testOrderDetail); 12 13 void UpdateTestOrderDetail(Guid testOrderDetailId, decimal subtotal); 14 15 void RemoveTestOrderDetail(Guid testOrderDetailId); 16 17 void Commit(); 18 19 void Verify(); 20 21 string Status { get; } 22 23 TestOrder TestOrder { set; } 24 } 25 }
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace Happy.Example.Domain.TestOrders 8 { 9 public partial class TestOrder 10 { 11 private abstract class TestOrderState : ITestOrderState 12 { 13 public virtual void AddTestOrderDetail(TestOrderDetail testOrderDetail) 14 { 15 this.ThrowInvalidOperationException(); 16 } 17 18 public virtual void UpdateTestOrderDetail(Guid testOrderDetailId, decimal subtotal) 19 { 20 this.ThrowInvalidOperationException(); 21 } 22 23 public virtual void RemoveTestOrderDetail(Guid testOrderDetailId) 24 { 25 this.ThrowInvalidOperationException(); 26 } 27 28 public virtual void Commit() 29 { 30 this.ThrowInvalidOperationException(); 31 } 32 33 public virtual void Verify() 34 { 35 this.ThrowInvalidOperationException(); 36 } 37 38 public abstract string Status { get; } 39 40 public TestOrder TestOrder { protected get; set; } 41 42 private void ThrowInvalidOperationException() 43 { 44 throw new InvalidOperationException(string.Format("處於【{0}】的訂單不能執行此操做!", this.Status)); 45 } 46 } 47 } 48 }
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace Happy.Example.Domain.TestOrders 8 { 9 public partial class TestOrder 10 { 11 private sealed class UnCommitted : TestOrderState 12 { 13 internal static readonly string UnCommittedStatus = "未提交"; 14 15 public override void AddTestOrderDetail(TestOrderDetail testOrderDetail) 16 { 17 this.TestOrder.DoAddTestOrderDetail(testOrderDetail); 18 } 19 20 public override void UpdateTestOrderDetail(Guid testOrderDetailId, decimal subtotal) 21 { 22 this.TestOrder.DoUpdateTestOrderDetail(testOrderDetailId, subtotal); 23 } 24 25 public override void RemoveTestOrderDetail(Guid testOrderDetailId) 26 { 27 this.TestOrder.DoRemoveTestOrderDetail(testOrderDetailId); 28 } 29 30 public override void Commit() 31 { 32 this.TestOrder.DoCommit(); 33 } 34 35 public override string Status 36 { 37 get { return UnCommittedStatus; } 38 } 39 } 40 } 41 }
採用封裝集合手法處理Total的同步問題。ide
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 using Happy.Domain; 8 using Happy.Domain.Tree; 9 using Happy.Infrastructure.ExtentionMethods; 10 using Happy.Example.Events.TestOrders; 11 12 namespace Happy.Example.Domain.TestOrders 13 { 14 public partial class TestOrder : AggregateRoot<Guid> 15 { 16 private ITestOrderState _orderState; 17 18 protected TestOrder() { } 19 20 public TestOrder(string orderCode, string customer) 21 { 22 orderCode.MustNotNullAndNotWhiteSpace("orderCode"); 23 customer.MustNotNullAndNotWhiteSpace("customer"); 24 25 this.Id = Guid.NewGuid(); 26 this.OrderCode = orderCode; 27 this.Customer = customer; 28 this.OrderState = TestOrderStateFactory.CreateUnCommittedTestOrderState(this); 29 this.TestOrderDetails = new List<TestOrderDetail>(); 30 } 31 32 public virtual System.String OrderCode { get; protected set; } 33 public virtual System.String Customer { get; protected set; } 34 public virtual System.Decimal Total { get; protected set; } 35 public virtual System.String Status { get; protected set; } 36 public virtual ICollection<TestOrderDetail> TestOrderDetails { get; protected set; } 37 38 private ITestOrderState OrderState 39 { 40 get 41 { 42 if (_orderState == null) 43 { 44 _orderState = TestOrderStateFactory.Create(this, this.Status); 45 } 46 47 return _orderState; 48 } 49 set 50 { 51 _orderState = value; 52 this.Status = value.Status; 53 } 54 } 55 56 public void AddTestOrderDetail(TestOrderDetail testOrderDetail) 57 { 58 this.OrderState.AddTestOrderDetail(testOrderDetail); 59 } 60 61 public void UpdateTestOrderDetail(Guid testOrderDetailId, decimal subtotal) 62 { 63 this.OrderState.UpdateTestOrderDetail(testOrderDetailId, subtotal); 64 } 65 66 public void RemoveTestOrderDetail(Guid testOrderDetailId) 67 { 68 this.OrderState.RemoveTestOrderDetail(testOrderDetailId); 69 } 70 71 public void Commit() 72 { 73 this.OrderState.Commit(); 74 } 75 76 public void Verify() 77 { 78 this.OrderState.Verify(); 79 } 80 81 private void DoAddTestOrderDetail(TestOrderDetail testOrderDetail) 82 { 83 this.TestOrderDetails.Add(testOrderDetail); 84 85 this.Total += testOrderDetail.Subtotal; 86 } 87 88 private void DoUpdateTestOrderDetail(Guid testOrderDetailId, decimal subtotal) 89 { 90 var testOrderDetail = this.TestOrderDetails.First(x => x.Id == testOrderDetailId); 91 92 this.Total -= testOrderDetail.Subtotal; 93 testOrderDetail.Subtotal = subtotal; 94 this.Total += testOrderDetail.Subtotal; 95 } 96 97 private void DoRemoveTestOrderDetail(Guid testOrderDetailId) 98 { 99 var testOrderDetail = this.TestOrderDetails.First(x => x.Id == testOrderDetailId); 100 101 this.TestOrderDetails.Remove(testOrderDetail); 102 this.Total -= testOrderDetail.Subtotal; 103 } 104 105 private void DoCommit() 106 { 107 this.OrderState = TestOrderStateFactory.CreatePendingVerificationTestOrderState(this); 108 } 109 110 private void DoVerify() 111 { 112 this.OrderState = TestOrderStateFactory.CreateVerifiedTestOrderState(this); 113 114 this.PublishEvent(new TestOrderVerified()); 115 } 116 } 117 }
寫這個簡單的Demo過程,遇到了不少小的決策,這篇文章就看作一個開頭吧,後邊重點介紹每一個決策點,在一篇文章中真的很難說完,喜歡看代碼的朋友,先去https://happy.codeplex.com/下載。ui