You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core观察者模式应用疑问:Transaction实体事件通知实现咨询

观察者模式在.NET Core领域事件中的应用建议

先给结论:观察者模式可行,但并非.NET Core中处理领域事件的最优选择

在.NET Core生态里,处理领域实体的事件通知有几种主流思路,咱们一步步拆解:

1. 直接实现IObservable<T>/IObserver<T>的优缺点

  • 优势:这是.NET框架内置的标准实现,遵循官方规范,代码风格统一,适合简单场景(比如只有少量观察者需要监听Transaction的变化)。
  • 劣势:
    • 领域实体直接依赖IObservable接口,会让领域层和.NET基础库耦合度上升,不符合领域驱动设计(DDD)中领域层独立的核心原则。
    • 手动管理订阅/取消订阅容易踩坑,比如忘记取消导致内存泄漏,尤其是在Web应用这类短生命周期场景下。
    • 原生IObservable以同步设计为主,很难优雅地实现异步事件处理。

2. 更推荐的方案:领域实体内置事件集合 + 事件总线分发

这是DDD场景下的主流做法,能完全隔离领域层与基础设施层,扩展性更强:

  • 核心步骤:
    1. 在Transaction实体内部维护一个私有事件集合(比如List<DomainEvent>),当交易创建、更新时,生成对应的领域事件(如TransactionCreatedEvent、TransactionUpdatedEvent)并添加到集合中。
    2. 提供公共方法(如GetDomainEvents())取出事件,同时清空集合(避免重复处理)。
    3. 在应用服务层,保存实体到数据库后,取出事件并通过事件总线(比如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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:48:19