Где «уровень бизнес-логики» вписывается в приложение MVC?

86

Во-первых, до того, как кто-то закричит, что я обманываю, мне было трудно выразить это простым заголовком. Другой заголовок мог бы быть «В чем разница между моделью предметной области и моделью MVC?» или "Что такое модель?"

Концептуально я понимаю, что Модель - это данные, используемые представлениями и контроллером. Помимо этого, существует множество различных мнений о том, что составляет модель. Что такое модель предметной области, модель приложения, модель представления, модель службы и т. Д.

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

Возьмем простой пример. AccountController, включенный в проект MVC по умолчанию. Я читал несколько мнений о том, что включенный код учетной записи плохо спроектирован, нарушает SRP и т. Д. И т. Д. Если бы нужно было разработать «правильную» модель членства для приложения MVC, что бы это было?

Как бы вы отделили службы ASP.NET (поставщик членства, поставщик ролей и т. Д.) От модели? Или бы вы вообще?

На мой взгляд, модель должна быть «чистой», возможно, с логикой проверки ... но должна быть отделена от бизнес-правил (кроме проверки). Например, предположим, что у вас есть бизнес-правило, которое гласит, что при создании новой учетной записи кому-то необходимо отправить электронное письмо. На мой взгляд, это не относится к модели. Так где это место?

Кто-нибудь хочет пролить свет на эту проблему?

Эрик Функенбуш
источник
1
Вот почему вам следует задать четыре отдельных вопроса.
Джон Фаррелл,
3
Ключевое слово - «почти». На самом деле это тот же вопрос, возможно, с подвопросами, использованными для иллюстрации основного вопроса.
Эрик Функенбуш
3
Модель - Вид - Контроллер. Есть репозиторий / BL View? Нет. Это контроллер? Нет. Что осталось :)? Это MVC, а не MSVC, не MRVC, не MBLVC. Всего три слоя. Итак, репозиторий является частью модели, а BL - частью модели. И вы можете сделать дополнительное разделение, но это делается внутри слоя модели.
LukLed
3
@LukeLed, @bslm - Не совсем. MVC не говорит, что не может быть других слоев, с которыми взаимодействует контроллер или модель.
Джон Фаррелл,
3
@LukLed - Не согласен - MVC - это просто шаблон уровня представления. Это не влияет на то, как вы структурируете другие слои, такие как BLL и DAL.
Кори Хаус

Ответы:

69

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

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

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

Речь идет о работе с кредитными картами - мне нужно потребовать cvv при обработке платежа, но я не могу сохранить cvv (за это взимается штраф в размере 50 000 долларов). Но я также хочу, чтобы вы могли редактировать свою кредитную карту - изменение адреса, имени или срока действия. Но вы не собираетесь давать мне номер или cvv при его редактировании, и я, конечно, не собираюсь помещать номер вашей кредитной карты в виде обычного текста на странице. В моем домене есть эти значения, необходимые для сохранения новой кредитной карты, потому что вы даете их мне, но моя модель редактирования даже не включает номер карты или CVV.

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

На мой взгляд, код контроллера должен быть только кодом, нацеленным на представление. Покажите это, скройте это и т. Д. Уровень обслуживания должен содержать бизнес-логику вашего приложения. Мне нравится, когда все это находится в одном месте, поэтому бизнес-правило легко изменить или настроить. Уровень репозитория должен быть относительно глупым - лишенным бизнес-логики и только запрашивать ваши данные и возвращать объекты вашего домена. Отделив модели представления от модели предметной области, вы получаете гораздо больше гибкости, когда дело касается настраиваемых правил проверки. Это также означает, что вам не нужно выгружать каждую часть данных в свое представление в скрытых полях и передавать их туда и обратно между клиентом и сервером (или перестраивать его на бэкэнде).

<% if (!String.IsNullOrEmpty(Model.SomeObject.SomeProperty) && 
    Model.SomeObject.SomeInt == 3 && ...) { %>

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

Джош
источник
Примерно зеркало того, что есть у меня в нашем корпоративном приложении MVC. N-уровневая архитектура. Приложение MVC взаимодействует только с бизнес-объектами и сервисами в многоуровневых областях.
Эд ДеГан
В основном то же самое и здесь. Отдельные проекты для определений, моделей, моделей представления, DAL и т. Д. Единственное отличие состоит в том, что мой DAL включает логику для выравнивания данных для Интернета для оптимизации распределения сложных данных для отчетов или пользовательских представлений клиентов. Теперь я избегаю хранить вещи в кэше приложений для таблиц поиска и т. Д. С веб-фермами и облаками Azure.
Роберт Ахманн
1
@Josh, было бы полезно, если бы вы могли показать снимок экрана вашего образца проекта?
Shaijut
@ Джош, а что, если в вашем проекте нет базы данных. Он взаимодействует со ссылками на службы. Все классы и методы предметной области взяты из этих ссылок. Подходит ли этот сценарий для многоуровневой структуры?
user6395764
17

Я слишком часто задавался вопросом, как именно элементы MVC вписываются в традиционную структуру веб-приложения, где у вас есть представления (страницы), контроллеры, службы и объекты данных (модель). Как вы сказали, существует множество версий.

Я полагаю, что путаница существует из-за вышеупомянутой широко принятой архитектуры, которая использует (предполагаемую) антипаттерн «модель анемичной области». Я не буду вдаваться в подробности «антипаттерна» анемичной модели данных (вы можете посмотреть на мою попытку объяснить вещи здесь (на основе Java, но актуально для любого языка)). Но вкратце это означает, что наша модель хранит только данные, а бизнес-логика размещена в сервисах / менеджерах.

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

  • вид - это пользовательский интерфейс
  • контроллер собирает входные данные пользовательского интерфейса, вызывает методы модели и отправляет ответ пользовательскому интерфейсу.
  • Модель - это наши бизнес-компоненты, содержащие данные, но также имеющие бизнес-логику.

Думаю, это отвечает на ваши основные вопросы. Все усложняется, когда мы добавляем еще несколько слоев, например слой репозитория. Часто предполагается, что он должен вызываться бизнес-логикой, размещенной в модели (и, следовательно, каждый объект домена имеет ссылку на репозиторий). В своей статье, которую я связал, я утверждаю, что это не совсем лучшая практика. И что на самом деле наличие служебного слоя - это неплохо. Между прочим, дизайн, управляемый доменом, не исключает уровень обслуживания, но он должен быть «тонким» и только координирующим объекты домена (так что здесь нет бизнес-логики).

Для парадигмы анемичной модели данных, которая широко принята (хорошо это или плохо), модель будет одновременно и уровнем сервиса, и вашими объектами данных.

Божо
источник
Отличный момент! Одно замечание: с Сервисами такая же неразбериха. По крайней мере службы могут быть службами приложений и службами домена. Служба приложений - это просто тонкая оболочка, которая собирает информацию из репозиториев и т. Д. Служба домена предоставляет бизнес-логику, которая использует комбинацию моделей домена или просто вещи, которые не всегда вписываются в модель домена.
Artru
что делать, если в вашем проекте нет базы данных. Он взаимодействует со ссылками на службы. Все классы и методы предметной области взяты из этих ссылок. Подходит ли этот сценарий для многоуровневой структуры?
user6395764
3

По моему мнению,

Модель -

Не должен содержать бизнес-логику, он должен быть подключаемым (сценарий типа WCF). Он используется для привязки к просмотру, поэтому у него должны быть свойства.

Бизнес-логика -

Он должен быть размещен на «уровне доменных служб», это вообще отдельный уровень. Также сюда добавим еще один слой «Application Services».

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

Итак, контроллер запросит у службы приложения модель, и поток будет выглядеть следующим образом:

    Controller->Application Services(using domain services)->Model
py2020
источник
2

Шаблон MVC и фреймворк Asp.net не делают различий в том, какой должна быть Модель.

Собственные примеры MS включают в модель классы устойчивости. Ваш вопрос о членстве в модели. Это зависит. Классы в вашей модели кому-то принадлежат? Есть ли связь между тем, кто входит в систему и какие данные отображаются? Есть ли фильтрация данных в редактируемой системе разрешений? Кто последний раз обновлял или редактировал объект, является частью вашего домена, поскольку кому-то еще нужно его увидеть, или что-то еще для поддержки серверной части?

Пример электронной почты тоже зависит. Вы знакомы с событиями предметной области или событиями в частности? У вас есть отдельный сервис для отправки писем? Является ли отправка электронного письма частью вашего домена или это проблема уровня приложения, выходящая за рамки вашей системы? Должен ли пользовательский интерфейс знать, было ли электронное письмо отправлено успешно или нет? Требуется ли повторная отправка писем, которые не могут быть отправлены? Нужно ли сохранять содержимое отправленного электронного письма для поддержки или обслуживания клиентов?

Эти типы вопросов слишком общие и субъективные, но я отвечаю, чтобы вы и все, кто проголосовал за вас, могли это понять.

Все ваши требования / сроки / ресурсы перетекают в архитектуру вашей системы. Даже модель дохода может иметь эффект. Вы также должны учитывать шаблон, по которому вы снимаете. DDD сильно отличается от приложений, использующих постоянство как модель, и все промежуточные значения также применимы для определенных приложений. Вы снимаете для тестирования приложения? Все это имеет эффект.

Джон Фаррелл
источник