Использование MVVM и DDD в приложении WPF без слишком большого количества классов

У меня есть приложение WPF, где я хочу применить MVVM для уровня представления и DDD для всего приложения. Я очень смущен тем, как я должен применять архитектуру. Можете ли вы дать мне несколько советов, поскольку мне кажется, что я полностью перепутал на данный момент со следующей попыткой дизайна:

У меня есть 4 слоя:

  • Presentation Layer: здесь находится мое клиентское приложение WPF.

  • Application Layer. Здесь у меня есть мои службы, которые предполагают связь с услугами домена для бизнес-правил и CRUD. Он работает просто как слой с антикоррупцией между слоями Presentation и Domain.

  • Domain Layer. Здесь у меня есть свои агрегированные объекты, объекты домена и некоторые службы, которые раскрывают бизнес-правила, такие как IsTooOld(Person person)

  • Infrastructure Layer. Это самый низкий уровень, здесь находится инфраструктура, IRepository, IEntity и т.д.

Позвольте создать простой сценарий с этими слоями на основе DDD: иметь объект Person в базе данных, отобразить его, CRUD в базе данных, проверить день рождения людей и показать его пользователю.


Уровень презентации

Я начну с части WPF. Я создаю следующие классы:

  • PersonView: вид XAML человека

  • PersonViewModel: ViewModel, который предоставляет функции для PersonView. PersonView связывается с этим, и этот ViewModel предоставляет значения из PersonModel

  • PersonModel. Это MVVM-модель, с которой моя PersonViewModel тесно связана с.


Уровень домена

Это достаточно хорошо для уровня представления. Теперь я хочу подключиться к базе данных, чтобы получить объект person, чтобы представить его.

Я должен создать:

  • PersonEntity в Domain Layer: агрегат для объекта базы данных, используемый для сопоставлений с базой данных. Он находится в слое Domain.

  • Person в Domain Layer: Это модель домена DDD. Я приведу здесь немного логики, и я не хочу отправлять объекты объектов, как предлагает DDD.


Уровень приложения

Хорошо, у меня уже есть модели на 3 человека, которые очень похожи друг на друга. Как насчет еще нескольких возможностей для доступа к данным и сервисов?

  • PersonService в Application Layer: когда мой уровень представления хочет взаимодействовать с этим слоем, ему необходимо преобразовать его PersonModel (модель MVVM) в Person (модель домена). Затем эта служба на прикладном уровне преобразует Person (модель домена) в PersonEntity (объект объекта) и выполняет CRUD с базой данных. Эта служба использует еще один PersonService (см. Ниже) на уровне домена для проверки/применения некоторых бизнес-правил.

  • PersonService в Domain Layer: этот уровень работает только с объектом домена Person. Он имеет правила, связанные с бизнесом, такие как bool IsTooOld(Person person).


Подводя итог, я получил 7 классов для простого сценария:

  • Presentation.WpfClient.View.PersonView
  • Presentation.WpfClient.ViewModel.PersonViewModel
  • Presentation.WpfClient.Model.PersonModel
  • Application.ApplicationServices.PersonService
  • Domain.Application.Services.PersonService
  • Domain.Application.Models.Person
  • Domain.Application.DbEntities.PersonEntity (причина, по которой я создал это, заключается в том, что я не могу использовать сопоставление для сложных объектов домена, поэтому я просто помещаю здесь аннотации данных вместо отображения объектов домена)

Это очень неудобно. Я не уверен, как мне переструктурировать его и принести пользу как дизайну, управляемому доменом, так и шаблонам MVVM. Я действительно застрял, и я действительно с нетерпением жду любых советов или примеров реальной жизни для применения как MVVM, так и проекта, управляемого доменом. Я также открыт для любой обратной связи для соглашений об именах или стратегий для минимизации этой большой работы для простых операций.

У меня все еще есть два конкретных вопроса:

  • Следует ли удалять модели из уровня представления (модели MVVM) и использовать только модели из уровня домена (модели DDD)? Разве это не нарушение MVVM в этот момент?

  • Должен ли я объединять модели сущности (базы данных) с моделями доменов? Разве это не нарушение DDD?


Обновление

Решения, принятые мной:

  • Использование модели домена для модели MVVM (удалено PersonModel)
  • Используйте внешние сопоставления для той же модели для базы данных (удалено PersonEntity добавлено PersonMappings). Использование модели persistence намного дороже, чем просто ее отображение. См. http://enterprisecraftsmanship.com/2016/04/05/having-the-domain-model-separate-from-the-persistence-model/ из ответа Владимира.

Наконец, это выглядит так:

  • Presentation.WpfClient.View.PersonView
  • Presentation.WpfClient.ViewModel.PersonViewModel
  • Application.ApplicationServices.PersonService (crud с некоторой логикой, связанной с приложением)
  • Application.ApplicationServices.Mappings (Здесь есть абстракции и отображения репозитория)
  • Domain.Application.People.Person (объект объекта в нем ограниченный контекст, объект достаточно умен, чтобы обрабатывать логику домена).

Ответ 1

Это слишком много классов для одного понятия.

Должен ли я удалять модели из уровня представления (модели MVVM) и использовать только модели из уровня домена (модели DDD)? Разве это не нарушение MVVM в этот момент?

Да, это предпочтительное решение - это много случаев, особенно если вы не используете механизм связи, такой как WCF. Никакое нарушение здесь, поскольку MVVM не налагает особую реализацию части модели.

Должен ли я объединять модели сущности (базы данных) с моделями доменов? Разве это не нарушение DDD?

Кроме того, да. Разделение объекта на два (объект домена и объект "постоянство" ) обычно приводит к чрезмерной сложности и модели анемичного домена. Здесь более подробно: Наличие модели домена, отделенной от модели сохранения.

В целом, я рекомендую вам посмотреть этот пример. Это похоже на то, что вам нужно: полноценное приложение, написанное в WPF с использованием MVVM и DDD.

Ответ 2

DDD наиболее полезен при решении проблем бизнес-класса. В реальном проекте его следует использовать более гибким способом, чтобы определить, насколько сложным является домен. Я бы хотел использовать подход с несколькими стратегиями для его принятия.

  • В большинстве случаев речь идет о данных CRUD с небольшим изменением структуры данных. Я бы использовал только:

    Уровень презентации: ViewModel
    Сервисный уровень: ViewModel ↔ Объект Domin
    Domain Layer: объект домена, такой же, как Entity

  • Для более сложного Домена, где есть много важной и многоразовой бизнес-логики для объекта Domain, я бы добавил базовый сервис (например, ваш Domain.Application.Services.PersonService).

  • Если для данных процесса существует сложная бизнес-логика для упрощения сопоставления данных между уровнем представления и уровнем Domin Layer. Я бы добавил еще одну модель в Service Layer, аналогичную вашей Presentation.WpfClient.Model.PersonModel.

Итак, в основном архитектура, которую вы сейчас собрали, готова для обработки дела, что ваш домен Person очень сложный в вашем проекте. Но я не вижу его так далеко от вашего описания.

Чтобы ответить на ваши вопросы:

  • Вы можете удалить Presentation.WpfClient.Model.PersonModel в своих моделях MVVM. Он не нарушает MVVM, потому что в этом случае ваш объект домена является моделью, и у вас есть Presentation.WpfClient.ViewModel.PersonViewModel как ViewModel.

  • Вы можете объединить объект Entity с объектом Domain, если ваш домен Person не имеет сложной бизнес-логики.