Мнение

Редактировал(а) Alexandr Fokin 2026/09/15 13:34

   
 

Мнение автора: на основании своего опыта я выступаю скорее за анемичную модель: когда сущность в основном контейнер для данных, почти не содержащий логику, и наборе команд/сервисов для взаимодействия с ними (и именно на команды ложиться ответственность за сохранение консистентности агрегатов).

Для меня вполне допустим следующий вариант: в доменной логике мы не создаем и не редактируем сущности напрямую, а делаем это через ISetter компонент. В контракт конкретного ISetter мы закладываем способы создания и изменения сущности. В таком случае у нас есть компонент, который указывает на контракт и допустимые способы взаимодействия с конкретной сущностью.

Пример поведения, располагаемого в ISetter:

  1. типизированные билдеры под конкретные сценарии использования (инварианты)
  2. взаимодействие со связанными сущностями (родительская-дочерняя) (добавление, смена родительской сущности)
  3. вычисляемые свойства (которые меняются при изменении полей).

У этого подхода еще есть плюс, связанный с Expression tree | Деревья выражений. А именно мы легко можем строить Expression (например для проекции или Update запроса) (открытые setter).

 
 
  1. Единая точка для взаимодействия с сущностью (агрегатом).
    Комментарии.
    Изменение в одном месте влияет на все (целостность).
  2. Наглядный интерфейс для взаимодействия (полный текущий набор правил).
// Entity rules (interaction interface)
interface IEntityServices
{
 // Set rules (single point of editing).
 ITEntitySetter Setter { get; }

 // Specification rules
 ITEntityConditions Conditions { get; }

 // Discrimination union (OneOf) for invariants.
 ITEntityOneOf { get; }
}
interface ITEntitySetter
{
  TEntity Create1(Create1Param parameters);
  TEntity Create2(Create2Param parameters);

 void SetProperty1(TEntity entity, TValue propertyValue);

 void SetProperty2(TEntity entity, SetProperty2Param param);
}

interface ITEntityCondition
{
 bool IsCondition1(TEntity entity);

 bool IsCondition2(TEntity entity, Conditition2Params param);
}

interface ITEntityOneOf
{
 void PropertyOneOf<TParameter>(
    TEntity entity,
    TParameter param,
    Action<param, TInvariant1Dto> invariant1Handler,
    Action<param, TInvariant2Dto> invariant2Handler)
}

 

Specification