.NET Core观察者模式应用疑问:Transaction实体事件通知实现咨询
观察者模式在.NET Core领域事件中的应用建议
先给结论:观察者模式可行,但并非.NET Core中处理领域事件的最优选择
在.NET Core生态里,处理领域实体的事件通知有几种主流思路,咱们一步步拆解:
1. 直接实现IObservable<T>/IObserver<T>的优缺点
- 优势:这是.NET框架内置的标准实现,遵循官方规范,代码风格统一,适合简单场景(比如只有少量观察者需要监听
Transaction的变化)。 - 劣势:
- 领域实体直接依赖
IObservable接口,会让领域层和.NET基础库耦合度上升,不符合领域驱动设计(DDD)中领域层独立的核心原则。 - 手动管理订阅/取消订阅容易踩坑,比如忘记取消导致内存泄漏,尤其是在Web应用这类短生命周期场景下。
- 原生
IObservable以同步设计为主,很难优雅地实现异步事件处理。
- 领域实体直接依赖
2. 更推荐的方案:领域实体内置事件集合 + 事件总线分发
这是DDD场景下的主流做法,能完全隔离领域层与基础设施层,扩展性更强:
- 核心步骤:
- 在
Transaction实体内部维护一个私有事件集合(比如List<DomainEvent>),当交易创建、更新时,生成对应的领域事件(如TransactionCreatedEvent、TransactionUpdatedEvent)并添加到集合中。 - 提供公共方法(如
GetDomainEvents())取出事件,同时清空集合(避免重复处理)。 - 在应用服务层,保存实体到数据库后,取出事件并通过事件总线(比如MediatR,或自定义简单总线)分发给对应的处理程序。
- 在
示例代码片段:
// 领域实体 public class Transaction { private List<DomainEvent> _domainEvents = new(); public Guid Id { get; private set; } public decimal Amount { get; private set; } public static Transaction Create(decimal amount) { var transaction = new Transaction { Id = Guid.NewGuid(), Amount = amount }; // 触发创建事件 _domainEvents.Add(new TransactionCreatedEvent(transaction.Id, amount)); return transaction; } public void UpdateAmount(decimal newAmount) { Amount = newAmount; // 触发更新事件 _domainEvents.Add(new TransactionUpdatedEvent(Id, newAmount)); } public IEnumerable<DomainEvent> GetDomainEvents() { var events = _domainEvents.ToList(); _domainEvents.Clear(); return events; } } // 领域事件基类 public abstract class DomainEvent { public DateTime OccurredOn { get; } = DateTime.UtcNow; } // 具体事件 public class TransactionCreatedEvent : DomainEvent { public Guid TransactionId { get; } public decimal Amount { get; } public TransactionCreatedEvent(Guid transactionId, decimal amount) { TransactionId = transactionId; Amount = amount; } }
应用服务层处理逻辑:
public class TransactionAppService { private readonly ITransactionRepository _transactionRepo; private readonly IMediator _mediator; public TransactionAppService(ITransactionRepository transactionRepo, IMediator mediator) { _transactionRepo = transactionRepo; _mediator = mediator; } public async Task CreateTransaction(decimal amount) { var transaction = Transaction.Create(amount); await _transactionRepo.SaveAsync(transaction); // 分发领域事件 var events = transaction.GetDomainEvents(); foreach (var evt in events) { await _mediator.Publish(evt); } } }
3. 什么时候适合用IObservable?
如果你的场景满足以下所有条件,可以考虑用原生观察者模式:
- 没有复杂的DDD架构要求,只是需要在实体变化时通知少量本地观察者。
- 不需要异步处理,所有观察者逻辑都是同步执行的。
- 能确保观察者的生命周期管理不会出问题(比如控制台应用这类长生命周期场景)。
总结
- 不建议在领域实体中直接实现
IObservable,会增加耦合度,限制后续扩展。 - 优先选择领域实体维护事件集合 + 事件总线分发的方案,这是.NET Core中处理领域事件的主流实践,像MediatR这类轻量级库能帮你轻松实现同步/异步事件处理,还完美适配依赖注入。
内容的提问来源于stack exchange,提问作者Sergio
相关产品推荐
相关产品推荐

