Шаг 8: Интерфейсы (контракты)
Order нужно сохранять в БД, но Domain не знает о базе данных (нет пакета EF Core). Решение: Domain определяет интерфейс (контракт «мне нужен кто-то, кто умеет сохранять заказы»), а Infrastructure реализует его. Это Dependency Inversion Principle.
IOrderRepository.cs
В папке Interfaces:
using OrderManagement.Domain.Entities;
namespace OrderManagement.Domain.Interfaces;
public interface IOrderRepository
{
Task<Order?> GetByIdAsync(
Guid id, CancellationToken ct = default);
Task<IReadOnlyList<Order>> GetByCustomerIdAsync(
string customerId, CancellationToken ct = default);
Task AddAsync(Order order, CancellationToken ct = default);
void Update(Order order);
void Remove(Order order);
}
Task<Order?> -- асинхронная операция, возвращающая Order или null. CancellationToken позволяет отменить операцию (клиент закрыл браузер). Репозиторий работает только с Aggregate Root -- нет отдельного IOrderItemRepository.
IUnitOfWork.cs
namespace OrderManagement.Domain.Interfaces;
public interface IUnitOfWork : IDisposable
{
Task<int> SaveChangesAsync(CancellationToken ct = default);
}
Unit of Work гарантирует атомарность: все изменения сохраняются в одной транзакции при вызове SaveChangesAsync. Если одна операция не удалась -- все откатываются.
Domain Layer завершён
OrderManagement.Domain/
├── Common/ (Entity, ValueObject, IAggregateRoot, IDomainEvent)
├── Entities/ (Order, OrderItem)
├── ValueObjects/ (Money, ShippingAddress, Email)
├── Enums/ (OrderStatus)
├── Events/ (OrderCreated, OrderConfirmed, OrderCancelled)
├── Exceptions/ (DomainException, OrderNotFoundException)
└── Interfaces/ (IOrderRepository, IUnitOfWork)
Зависимости: только MediatR.Contracts. Никакого EF Core, ASP.NET, Azure SDK.