简单来,拿登录和转账来说说? ...
那我就拿转帐来说说吧:
先描述一下转帐的业务需求:
1)源账户扣除转账金额,当然首先需要先判断源账户余额是否足够,如果不够,则无法转账;
2)目标账户增加转账金额;
3)为源账户生成一笔转账记录;
4)为目标账户生成一笔转账记录;
好了,如果从“对象+关系引擎+消息机制”的角度来设计这个需求的话,我觉得可以这样:
1)用BankAccount表示银行帐号类,用EventProcesser表示关系引擎,用transferEvent表示转帐的消息;
2)创建并发送一个转账消息给关系引擎,该消息包括源帐号,目标帐号,转帐金额,转账日期。示例代码如下:
EventProcesser.ProcessEvent(new TransferEvent(bankAccount1.Id, bankAccount2.Id, 1000, DateTime.Now));
3)关系引擎智能的解析该消息,然后自动获取源帐号对象和目标帐号对象,然后通知它们分别响应该消息;对于源帐号对象来说,它会响应该消息并做“转出钱”的操作,并且给自己创建一笔转帐记录;对于目标帐号来说,它会响应该消息并做“转入钱”的操作,并且给自己创建一笔转帐记录;
理想情况下,只要做这三步就可以实现转帐需求了。但实际上我们的关系引擎没有足够智能,它无法智能地分析这个转帐的消息。所以,我现在的做法是需要预先在程序启动时告诉关系引擎:转帐消息和该消息的响应者之间的关系,比如如何从该消息中提取源帐号对象和目标帐号对象,以及需要调用源帐号对象与目标帐号对象的哪个响应方法。
以下是我实现的具体代码(C#),奇怪,为什么jdon网站只支持插入java代码呢?难道是对C#或.NET有歧视,呵呵:
1 public class TransferEvent : DomainEvent //转帐消息 2 { 3 public TransferEvent(Guid fromBankAccountId, Guid toBankAccountId, double moneyAmount, DateTime transferDate) 4 { 5 this.FromBankAccountId = fromBankAccountId; 6 this.ToBankAccountId = toBankAccountId; 7 this.MoneyAmount = moneyAmount; 8 this.TransferDate = transferDate; 9 } 10 public Guid FromBankAccountId { get; private set; } 11 public Guid ToBankAccountId { get; private set; } 12 public double MoneyAmount { get; private set; } 13 public DateTime TransferDate { get; private set; } 14 } 15 public class BankAccount : DomainObject<Guid> //银行帐号类 16 { 17 #region Private Variables 18 19 private List<TransferHistory> transferHistories; 20 21 #endregion 22 23 #region Constructors 24 25 public BankAccount(Guid customerId) 26 : this(customerId, 0D, new List<TransferHistory>()) 27 { 28 } 29 public BankAccount(Guid customerId, double moneyAmount, IEnumerable<TransferHistory> transferHistories) 30 : base(Guid.NewGuid()) 31 { 32 this.CustomerId = customerId; 33 this.MoneyAmount = moneyAmount; 34 this.transferHistories = new List<TransferHistory>(transferHistories); 35 } 36 37 #endregion 38 39 #region Public Properties 40 41 public Guid CustomerId { get; private set; } 42 [TrackingProperty] 43 public IEnumerable<TransferHistory> TransferHistories 44 { 45 get 46 { 47 return transferHistories.AsReadOnly(); 48 } 49 } 50 [TrackingProperty] 51 public double MoneyAmount { get; private set; } 52 53 #endregion 54 55 #region Event Handlers 56 57 private void TransferTo(TransferEvent evnt) //源帐号响应转帐消息(做转出钱的操作) 58 { 59 if (this.Id == evnt.FromBankAccountId) 60 { 61 DecreaseMoney(evnt.MoneyAmount); 62 transferHistories.Add( 63 new TransferHistory( 64 evnt.FromBankAccountId, 65 evnt.ToBankAccountId, 66 evnt.MoneyAmount, 67 evnt.TransferDate)); 68 } 69 } 70 private void TransferFrom(TransferEvent evnt) //目标帐号响应转帐消息(做转入钱的操作) 71 { 72 if (this.Id == evnt.ToBankAccountId) 73 { 74 IncreaseMoney(evnt.MoneyAmount); 75 transferHistories.Add( 76 new TransferHistory( 77 evnt.FromBankAccountId, 78 evnt.ToBankAccountId, 79 evnt.MoneyAmount, 80 evnt.TransferDate)); 81 } 82 } 83 84 #endregion 85 86 #region Private Methods 87 88 private void DecreaseMoney(double moneyAmount) 89 { 90 if (this.MoneyAmount < moneyAmount) 91 { 92 throw new NotSupportedException("账户余额不足。"); 93 } 94 this.MoneyAmount -= moneyAmount; 95 } 96 private void IncreaseMoney(double moneyAmount) 97 { 98 this.MoneyAmount += moneyAmount; 99 } 100 101 #endregion 102 } 103 public class TransferHistory : ValueObject //转帐记录,是一个值对象 104 { 105 #region Constructors 106 107 public TransferHistory(Guid fromAccountId, 108 Guid toAccountId, 109 double moneyAmount, 110 DateTime transferDate) 111 { 112 this.FromAccountId = fromAccountId; 113 this.ToAccountId = toAccountId; 114 this.MoneyAmount = moneyAmount; 115 this.TransferDate = transferDate; 116 } 117 118 #endregion 119 120 #region Public Properties 121 122 public Guid FromAccountId { get; private set; } 123 public Guid ToAccountId { get; private set; } 124 public double MoneyAmount { get; private set; } 125 public DateTime TransferDate { get; private set; } 126 127 #endregion 128 129 #region Infrastructure 130 131 protected override IEnumerable<object> GetAtomicValues() 132 { 133 yield return FromAccountId; 134 yield return ToAccountId; 135 yield return MoneyAmount; 136 yield return TransferDate; 137 } 138 139 #endregion 140 }
//创建消息和发送消息的代码: EventProcesser.ProcessEvent(new TransferEvent(bankAccount1.Id, bankAccount2.Id, 1000, DateTime.Now));
//创建关系并将关系告诉关系引擎的代码: RegisterObjectEventMappingItem<TransferEvent, BankAccount>( 2 new GetDomainObjectIdEventHandlerInfo<TransferEvent> 3 { 4 GetDomainObjectId = evnt => evnt.FromBankAccountId, //告诉框架源银行帐号对象是根据消息的FromBankAccountId作为唯一标识来获取的 5 EventHandlerName = "TransferTo" //告诉响应的方法 6 }, 7 new GetDomainObjectIdEventHandlerInfo<TransferEvent> 8 { 9 GetDomainObjectId = evnt => evnt.ToBankAccountId, //告诉框架目标银行帐号对象是根据消息的ToBankAccountId作为唯一标识来获取的 10 EventHandlerName = "TransferFrom" //告诉响应的方法 11 } 12 );
|
如果你要看我具体的代码,可以具体参考我在博客园的一篇文章,那里讲的比较具体。http://www.cnblogs.com/netfocus/archive/2011/04/17/2019152.html
[该贴被tangxuehua于2011-04-26 13:08修改过]
[该贴被tangxuehua于2011-04-26 13:14修改过]