Ответ
Богатая доменная модель — это архитектурный подход в Domain-Driven Design (DDD), при котором бизнес-логика (поведение) инкапсулирована внутри самих сущностей и объектов-значений предметной области, а не размещается в отдельном сервисном слое (так называемая "анемичная модель").
Суть подхода: Доменные объекты — это не просто "контейнеры для данных" (DTO), а полноценные объекты с методами, которые реализуют правила и инварианты предметной области.
Сравнение с анемичной моделью:
// АНЕМИЧНАЯ МОДЕЛЬ (Anti-pattern): Данные и логика разделены.
public class Order // Только данные, геттеры/сеттеры
{
public int Id { get; set; }
public decimal Total { get; set; }
public List<OrderItem> Items { get; set; } = new();
}
public class OrderService // Вся логика вынесена в сервис
{
public void AddItem(Order order, Product product, int qty)
{
// Проверки и расчеты здесь
if (qty <= 0) throw new Exception();
order.Items.Add(new OrderItem(product, qty));
order.Total += product.Price * qty;
}
}
// БОГАТАЯ ДОМЕННАЯ МОДЕЛЬ: Логика внутри сущности.
public class Order
{
public int Id { get; private set; } // Сеттер приватный
public decimal Total { get; private set; }
private readonly List<OrderItem> _items = new(); // Инкапсуляция коллекции
public IReadOnlyList<OrderItem> Items => _items.AsReadOnly();
// Бизнес-метод, отвечающий за добавление товара. Инкапсулирует правила.
public void AddItem(Product product, int quantity)
{
// 1. Проверка инвариантов (валидация внутри домена)
if (product == null) throw new ArgumentNullException(nameof(product));
if (quantity <= 0) throw new ArgumentException("Количество должно быть положительным", nameof(quantity));
if (!product.IsInStock) throw new InvalidOperationException("Товара нет в наличии");
// 2. Создание объекта-значения OrderItem
var item = new OrderItem(product.Id, product.Price, quantity);
// 3. Изменение состояния сущности
_items.Add(item);
Total += item.Subtotal;
// 4. Возможность генерации доменного события
// DomainEvents.Raise(new OrderItemAddedEvent(this, item));
}
// Другой бизнес-метод
public void ApplyDiscount(decimal discountPercent)
{
if (discountPercent < 0 || discountPercent > 100)
throw new ArgumentException("Неверный процент скидки");
Total *= (1 - discountPercent / 100);
}
}
Преимущества богатой модели:
- Высокая связность: Данные и операции над ними находятся в одном месте.
- Инкапсуляция: Состояние объекта защищено от некорректного изменения извне.
- Выразительность: Код моделирует реальные бизнес-процессы, его легче понимать.
- Тестируемость: Легко тестировать единицы бизнес-логики в изоляции.
Когда использовать? В сложных проектах с насыщенной и часто меняющейся бизнес-логикой, где важна чистота архитектуры и долгосрочная поддерживаемость.