上面的代码不算复杂,它根据上面的分析和描述,实现了IAggregateRootWithEventSourcing接口,篇幅原因,就不多做解释了,不过有几点还是可以鉴赏一下的:
使用Lazy类型来保证领域事件处理器的容器在整个聚合生命周期中只初始化一次
通过lock语句和Interlocked.Exchange来保证类型的线程安全和数值的原子操作
聚合根被构造的时候,会找到当前类型中所有标记了HandlesInlineAttribute特性,并具有一定特征的函数,将它们作为领域事件的内联处理器,注册到容器中
每当聚合中的某个业务操作(方法)需要更改聚合中的状态时,就调用Raise方法来产生领域事件,由对应的内联处理器捕获领域事件,并在处理器方法中设置聚合的状态
Replay方法会遍历所有给点的领域事件,调用HandleEvent方法,实现事件回放
现在,我们已经实现了CQRS架构下的聚合与聚合根,虽然实际上这个结构有可能比我们的实现更为复杂,但是目前的这个设计已经能够满足我们进一步研究讨论的需求了。下面,我们再更进一步,看看CQRS中仓储应该如何实现。
仓储实现初探为什么说是“初探”?因为我们目前打算实现的仓储暂时不包含事件派发的逻辑,这部分内容我会在后续文章中讲解。首先看看,仓储的接口是什么样的。在CQRS架构中,仓储只具备两种操作:
保存聚合
根据聚合ID(也就是聚合根的ID)值,获取聚合对象
你或许会问,那根据某个条件查询满足该条件的所有聚合对象呢?注意,这是CQRS架构中查询部分的职责,不属于我们的讨论范围。
通常,仓储的接口定义如下:
public interface IRepository { Task SaveAsync<TAggregateRoot>(TAggregateRoot aggregateRoot) where TAggregateRoot : class, IAggregateRootWithEventSourcing; Task<TAggregateRoot> GetByIdAsync<TAggregateRoot>(Guid id) where TAggregateRoot : class, IAggregateRootWithEventSourcing; }与之前领域事件的设计类似,我们为仓储定义一个抽象类,所有仓储的实现都应该基于这个抽象类:
public abstract class Repository : IRepository { protected Repository() { } public async Task<TAggregateRoot> GetByIdAsync<TAggregateRoot>(Guid id) where TAggregateRoot : class, IAggregateRootWithEventSourcing { var domainEvents = await LoadDomainEventsAsync(typeof(TAggregateRoot), id); var aggregateRoot = ActivateAggregateRoot<TAggregateRoot>(); aggregateRoot.Replay(domainEvents); return aggregateRoot; } public async Task SaveAsync<TAggregateRoot>(TAggregateRoot aggregateRoot) where TAggregateRoot : class, IAggregateRootWithEventSourcing { var domainEvents = aggregateRoot.UncommittedEvents; await this.PersistDomainEventsAsync(domainEvents); aggregateRoot.PersistedVersion = aggregateRoot.Version; aggregateRoot.Purge(); } protected abstract Task<IEnumerable<IDomainEvent>> LoadDomainEventsAsync(Type aggregateRootType, Guid id); protected abstract Task PersistDomainEventsAsync(IEnumerable<IDomainEvent> domainEvents); private TAggregateRoot ActivateAggregateRoot<TAggregateRoot>() where TAggregateRoot : class, IAggregateRootWithEventSourcing { var constructors = from ctor in typeof(TAggregateRoot).GetTypeInfo().GetConstructors() let parameters = ctor.GetParameters() where parameters.Length == 0 || (parameters.Length == 1 && parameters[0].ParameterType == typeof(Guid)) select new { ConstructorInfo = ctor, ParameterCount = parameters.Length }; if (constructors.Count() > 0) { TAggregateRoot aggregateRoot; var constructorDefinition = constructors.First(); if (constructorDefinition.ParameterCount == 0) { aggregateRoot = (TAggregateRoot)constructorDefinition.ConstructorInfo.Invoke(null); } else { aggregateRoot = (TAggregateRoot)constructorDefinition.ConstructorInfo.Invoke(new object[] { Guid.NewGuid() }); } // 将AggregateRoot下的所有事件清除。事实上,在AggregateRoot的构造函数中,已经产生了AggregateCreatedEvent。 aggregateRoot.Purge(); return aggregateRoot; } return null; } }