6.11. Доменная модель
Доменная модель
Когда определяется и создаётся модель, она строится на основе некой сущности.
Такая сущность может быть чем угодно, и называется она Entity.
Модели в первую очередь являются доменными объектами. Поэтому понятия «модель», «сущность», «объект» очень тесно связаны между собой в концепции работы ORM.
Объект (Object), как мы помним, это экземпляр класса, представляющий конкретную сущность в программе. У него есть состояние (атрибуты) и поведение (методы). Он существует в памяти во время выполнения программы. Он есть во всех ООП-языках и может быть как простым вспомогательным, так и полноценной бизнес-сущностью.
Сущность (Entity) — это объект, который имеет уникальную идентификацию (ID) и жизненный цикл, даже если его данные изменяются. Сущность определяется не по своим атрибутам, а по уникальному идентификатору. Даже если все данные объекта поменять, он остаётся той же сущностью, потому что ID не изменился. Сущности можно встретить в ORM-фреймворках, а в БД обычно отображается на таблицу, где Id как раз первичный ключ.
Модель (Model) — это абстракция, описывающая структуру данных и часто используемая для передачи данных между слоями приложения. Она может быть просто контейнером данных, может совпадать с сущностью, и часто используется как «прокладка» между UI и бизнес-логикой, особенно в архитектуре MVC.
Доменная модель - это центральная часть бизнес-логики приложения, которая описывает сущности, их поведение, правила и взаимодействие между ними. Элементы такой модели называются доменными объектами.
Domain - это предметная область, то есть реальные процессы, которыми занимается ваше приложение. К примеру, в интернет-магазине это Товар, Заказ, Пользователь, Корзина, в банковском приложении Счёт, Перевод, Клиент, Транзакция, в мессенджере Сообщение, Чат, Пользователь, UserConnection.
В доменной модели есть ряд основных элементов.
- Сущности (Entities), представляющие собой объекты с уникальным идентификатором. К примеру,
User {Id, Name}- это пользователь, и у каждого есть Id. - Значения (Value Objects), объекты без собственного ID, определяемые своими атрибутами, к примеру, Адрес, Деньги, Цвет.
- Агрегаты (Aggregates) - группы связанных объектов, у которых есть «корневая сущность» (aggregate root). Пример - Заказ будет корень агрегата, включающий Позиции заказа.
- Сервисы предметной области (Domain Services), логика, не принадлежащая конкретной сущности. Пример - Рассчитать стоимость доставки, Проверить доступность товара.
- Правила и инварианты - условия, которые должны всегда соблюдаться, к примеру Баланс счёта не может быть отрицательным.
- События предметной области (Domain Events) - это события, происходящие в домене, к примеру, Пользователь зарегистрирован, Заказ создан.
Доменная модель позволяет изолировать бизнес-логику от технической реализации, благодаря чему изменения в UI или базе данных не влияют на саму логику работы системы.
Работе с доменами посвящены даже паттерны вроде DDD (Domain-Driven Design), и можно использовать доменную модель в паттернах Репозиторий (Repository), Фабрика (Factory).
Пример доменной модели - Пользователь:
public class User
{
public Guid Id { get; }
public string Email { get; private set; }
public bool IsEmailConfirmed { get; private set; }
public User(Guid id, string email)
{
if (string.IsNullOrWhiteSpace(email))
throw new ArgumentException("Email cannot be empty", nameof(email));
Id = id;
Email = email;
IsEmailConfirmed = false;
}
public void ConfirmEmail()
{
if (IsEmailConfirmed)
throw new InvalidOperationException("Email already confirmed");
IsEmailConfirmed = true;
}
}
В этом примере User - сущность, ConfirmEmail() - метод, реализующий бизнес-правило, а проверка Email является инвариантом.
Таким образом, доменная модель представляет собой отделение от слоя приложения, инфраструктуры, API и UI.