Интерфейс с сервисным уровнем или самими объектами домена? (DDD)

Я все еще изучаю DDD, и у меня есть два (возможно, простых) вопроса:

Если Фабрика создает новые экземпляры объектов / графиков / агрегатов, но также "восстанавливает" объекты / графы из репозитория, то:

(1) Вызывает ли функция / задания / задачи / единицу работы вашего уровня обслуживания на Фабрику или поведенческий метод в экземпляре Entity или функцию DomainService? Я заблудился относительно стека вызовов, основанного на ответственности этих компонентов.

(2) Есть ли у экземпляров сущностей даже "поведенческие методы", как описано выше? Например, имеет ли пост p.UpdatePost(string bodyText) или это не касается модели предметной области и поэтому то же самое должно быть достигнуто с помощью репозитория? Или функция сервисного уровня, должна ли она вызывать репозиторий в этом случае, а у экземпляра сущности просто есть поведенческие методы, специфичные для домена, а не постоянства? Но тогда почему звучит так, будто "обновление сообщения" является функцией домена, если это цель пользователя?

Вы можете видеть, что я повсюду. Пожалуйста помоги.

1 ответ

Решение

(1) Вызывает ли функция / задания / задачи / единицу работы вашего уровня обслуживания на Фабрику или поведенческий метод в экземпляре Entity или функцию DomainService? Я заблудился относительно стека вызовов, основанного на ответственности этих компонентов.

Обычно - верхний уровень извлекает необходимый агрегатный корень и вызывает на нем функцию. Иногда верхний уровень извлекает несколько агрегатных корней и передает их службе домена, но не часто, потому что служба домена является довольно убедительным признаком того, что существует нераспознанный агрегатный корень. В конце - верхний уровень обеспечивает сохранение совокупного корня.

(2) Есть ли у экземпляров сущностей даже "поведенческие методы", как описано выше? Например, имеет ли Post p.UpdatePost(string bodyText) или это не касается модели предметной области, и поэтому то же самое должно быть достигнуто с помощью репозитория? Или функция сервисного уровня, должна ли она вызывать репозиторий в этом случае, а у экземпляра сущности просто есть поведенческие методы, специфичные для домена, а не постоянства? Но тогда почему звучит так, будто "обновление сообщения" является функцией домена, если это цель пользователя?

Да, они делают. Доменная модель должна знать об изменениях своего состояния. И это гораздо выгоднее, как кажется на первый взгляд. Самое замечательное в этом то, что вы получаете балл расширяемости. Если клиент через неделю перейдет к Вам и скажет, что он хочет, чтобы система проверяла дополнительные вещи, когда пользователь обновляет сообщение, - вместо поиска каждой строки post.bodyText="new value", Вы сможете идти прямо к post.UpdatePost метод и прикрепить необходимые вещи там.

С другой стороны - CRUD не является взаимоисключающим с доменным дизайном. Например, в моем приложении управление пользователями и их ролями неинтересно, и я даже не пытаюсь их детально моделировать. Вы должны распознать части, которые важны для бизнеса. Ваше приложение описывает и работает с ним.

Имейте в виду, что управляемый доменом дизайн имеет смысл только для сложных приложений. Простое приложение блога не нуждается в этом.

(3) Я ошибаюсь, полагая, что сервисный уровень (не доменные сервисы) должен инкапсулировать, как интерфейс взаимодействует с доменным уровнем?

На мой взгляд, сервисы приложений больше предназначены для организации инфраструктуры. Если инфраструктура не задействована - служба приложений теряет ценность:

Прикладные услуги в основном это просто фасады. И каждый фасад плох, если сложность добавляет сложностей, которые он решает.


Внутри домена:

//aggregate root is persistence ignorant. 
//it shouldn't reference repository directly
public class Customer{
  public string Name {get; private set;}
  public static Customer Register(string name){
    return new Customer(name);
  }
  protected Customer(string name){
    //here it's aware of state changes.
    //aggregate root changes it's own state
    //instead of having state changed from outside
    //through public properties
    this.Name=name;
  }
}

//domain model contains abstraction of persistence
public interface ICustomerRepository{
  void Save(Customer customer);
}

За пределами домена:

public class CustomerRepository:ICustomerRepository{
  //here we actually save state of customer into database/cloud/xml/whatever
  public void Save(Customer customer){
    //note that we do not change state of customer, we just persist it here
    _voodoo.StoreItSomehow(customer);
  }
}

//asp.net mvc controller
public class CustomerController{
  public CustomerController(ICustomerRepository repository){
    if (repository==null)throw new ArgumentNullException();
    _repository=repository;
  }
  public ActionResult Register(string name){
    var customer=Customer.Register(name);
    _repository.Save(customer);
  }
}
Другие вопросы по тегам