Что такое анемичная модель предметной области?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое анемичная модель предметной области?
Анемичная модель предметной области (Anemic Domain Model) — это антипаттерн в объектно-ориентированном программировании, при котором классы, представляющие бизнес-сущности (например, Order, User, Product), содержат только данные (поля/свойства) и практически не содержат бизнес-логики. Вся логика обработки этих данных выносится в отдельные сервисные классы (Service Layer), превращая сущности в простые контейнеры для данных. Это противоречит принципам богатой модели предметной области (Rich Domain Model), где сущности инкапсулируют и данные, и поведение.
Ключевые характеристики анемичной модели
- Сущности как DTO (Data Transfer Object): Классы состоят в основном из публичных свойств с get/set, напоминая структуры данных.
- Отсутствие инкапсуляции: Данные открыты для модификации извне, нет контроля за их состоянием.
- Логика в сервисах: Бизнес-правила реализованы в отдельных классах-сервисах, которые манипулируют анемичными сущностями.
Пример анемичной модели
Рассмотрим пример на C#. Анемичная сущность Order:
public class Order
{
public int Id { get; set; }
public string CustomerName { get; set; }
public decimal TotalAmount { get; set; }
public bool IsPaid { get; set; }
public List<OrderItem> Items { get; set; } = new();
}
public class OrderItem
{
public int ProductId { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
}
Сервис с бизнес-логикой:
public class OrderService
{
public void ApplyDiscount(Order order, decimal discountPercent)
{
if (discountPercent < 0 || discountPercent > 50)
throw new ArgumentException("Discount must be between 0 and 50%.");
order.TotalAmount *= (1 - discountPercent / 100);
}
public void AddItem(Order order, OrderItem item)
{
if (order.IsPaid)
throw new InvalidOperationException("Cannot modify paid order.");
order.Items.Add(item);
order.TotalAmount += item.Price * item.Quantity;
}
}
Проблемы анемичной модели
-
Нарушение ООП-принципов:
- Инкапсуляция: данные открыты, их можно изменить в обход бизнес-правил.
- Поведение отделено от данных, что усложняет понимание системы.
-
Сложность поддержки:
- Логика размазана по сервисам, изменения требуют правки в нескольких местах.
- Нет гарантии целостности данных (например, можно напрямую установить
order.TotalAmount = -100).
-
Тестирование:
- Сервисы становятся "божественными классами" с множеством зависимостей, их сложно тестировать изолированно.
-
Отсутствие доменного языка:
- Код не отражает реальные бизнес-процессы, становясь процедурным.
Альтернатива: Богатая модель предметной области
В богатой модели сущности инкапсулируют и данные, и поведение:
public class Order
{
public int Id { get; private set; }
public string CustomerName { get; private set; }
public decimal TotalAmount { get; private set; }
public bool IsPaid { get; private set; }
private readonly List<OrderItem> _items = new();
public IReadOnlyList<OrderItem> Items => _items.AsReadOnly();
public Order(string customerName)
{
CustomerName = customerName;
}
public void AddItem(int productId, int quantity, decimal price)
{
if (IsPaid)
throw new InvalidOperationException("Cannot modify paid order.");
_items.Add(new OrderItem(productId, quantity, price));
TotalAmount += price * quantity;
}
public void ApplyDiscount(decimal discountPercent)
{
if (discountPercent < 0 || discountPercent > 50)
throw new ArgumentException("Discount must be between 0 and 50%.");
TotalAmount *= (1 - discountPercent / 100);
}
public void MarkAsPaid() => IsPaid = true;
}
public class OrderItem
{
public int ProductId { get; }
public int Quantity { get; }
public decimal Price { get; }
public OrderItem(int productId, int quantity, decimal price)
{
ProductId = productId;
Quantity = quantity > 0 ? quantity : throw new ArgumentException("Quantity must be positive.");
Price = price >= 0 ? price : throw new ArgumentException("Price cannot be negative.");
}
}
Когда анемичная модель может быть оправдана?
- Простые CRUD-приложения без сложной бизнес-логики.
- Сценарии с ORM (например, Entity Framework), где сущности часто проектируются как анемичные для удобства маппинга.
- Архитектура CQRS, где команды и запросы разделены: для запросов используются DTO, а команды работают через агрегаты с поведением.
Заключение
Анемичная модель — это процедурный стиль в объектной одежде. Хотя она может упростить начальную разработку, в долгосрочной перспективе приводит к снижению гибкости и увеличению энтропии кода. Богатая модель, основанная на принципах DDD (Domain-Driven Design), обеспечивает лучшую инкапсуляцию, тестируемость и соответствие бизнес-требованиям. Выбор подхода зависит от сложности предметной области: для простых задач анемичная модель приемлема, для сложных — предпочтительна богатая.