Толстая модель/тонкий контроллер против сервисного уровня

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

Недавно мы начали работать над проектами MVC 3, и у нас были дебаты, где какую логику разместить. Я столкнулся с тонкой архитектурой контроллера / модели FAT и задался вопросом, как будет вписываться сервисный уровень.

Вариант 1 — Модель общается с сервисами

Контроллер тонкий, вызывает методы на моделях. Модели «знают», как загружать себя из БД и общаться с репозиториями или сервисами. Например. CustomerModel имеет метод Load(id) и загружает клиента и некоторые дочерние объекты, такие как GetContracts().

Вариант 2. Контроллер общается со службами

Контроллер запрашивает службы для извлечения объектов модели. Логика загрузки/сохранения и т.д. находится в сервисном слое. Модель представляет собой чистую модель объекта только с данными.

Почему вариант 1 был бы лучшим выбором, особенно когда мы говорим о корпоративных приложениях, мой опыт подсказывает мне, что нужно разделять проблемы, сохранять модели и контроллеры как можно более тонкими и иметь специализированные службы, выполняющие бизнес-логику (включая взаимодействие с БД)

Спасибо за все советы и ссылки на хорошие ресурсы.


person PeterFromCologne    schedule 04.01.2012    source источник


Ответы (4)


Все это зависит от намерения и требований вашего приложения.

Тем не менее, вот мое предложение для «средних масштабов» (не местный ресторан и не Twitter/Facebook) веб-приложений.

  1. Бережливое моделирование домена

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

    «Модель» в MVC наиболее точно означает модель, о которой знает контроллер и, следовательно, модель, предназначенную для представления.

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

    В более крупных приложениях разработчики часто используют принципы архитектуры MVVM и начинают использовать отдельные объекты модели представления. Контроллеры часто вызывают службы среднего уровня, которые работают с невидимыми сущностями ниже. В этом сценарии буква M в MVC наиболее точно означает модель представления.

  2. Надежный сервисный уровень

    Это означает не ожиревшую логику, а хорошо написанные одноцелевые сервисы. Хотя кодирование вашей бизнес-логики в службах за пределами модели немного более «процедурно», чем в чистом «ООП», оно очень помогает при слабой связи, тестировании и гибком развертывании (например, развертывании n-уровневого).

    В моей личной практике я кодирую сервисы как на уровне данных, что я считаю своим поведенческим моделированием объектов POCO (механика постоянства, низкоуровневая проверка и т. д.), так и сервисы более высокого уровня (функция бизнес-процесса) ближе к механика MVC.

  3. Бережливые контроллеры

    Я удостоверяюсь, что мой контроллер — это просто тренер, в том смысле, что он не является ни play (сервисами), ни player (моделью сущности или моделью представления). ), а просто решает, кто и какую позицию играет. Мои контроллеры делают две вещи:

    1. Службы вызовов, взаимодействующие с моделями объектов/доменов.

    2. Подготовьте модель представления для соответствующего представления.

    Даже аутентифицированные/авторизованные действия контроллера выполняются с помощью внедренных сервисов/атрибутов.


ИЗМЕНИТЬ 1:

Имейте в виду, что это не означает, что ваша модель объекта/доменной области является или должна быть анемичной. Приветствуются ORM, репозитории и фабрики, валидация или государственная механика. Это означает, что только для приложений среднего масштаба модель в MVC представляет собой модель, предназначенную для контроллера, для передачи вашему представлению.

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

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


РЕДАКТИРОВАТЬ 2:

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


ИЗМЕНИТЬ 3:

Я хотел бы отметить, что это объяснение и совет относятся к контексту серверной архитектуры MVC, такой как ASP.Net, а не к клиентским платформам, таким как Knockout или Backbone.

person one.beat.consumer    schedule 12.01.2012
comment
Это почти тот же шаблон проектирования, который я использую, за исключением того, что контроллер не знает репозиторий. Контроллер взаимодействует только со службами, которые, в свою очередь, взаимодействуют с репозиториями. - person Lester; 12.01.2012
comment
@Lester Я отредактировал, чтобы прояснить это. В 95% случаев мой тоже нет, идея в том, что сервисы работают. В небольших приложениях это может быть излишним, но это хорошая практика для всех, и ее гораздо проще поддерживать с помощью контейнера IoC. - person one.beat.consumer; 12.01.2012
comment
+1 @one.beat.consumer: это тот же подход, который я использую в своих проектах ... иногда слишком строгое отношение к правилам приводит к чрезмерно сложным решениям, и вы можете получить больше преимуществ от проверенного в реальном мире решения, которое не совсем соответствует шаблонам GOF - person themarcuz; 12.01.2012
comment
M MVC не для модели представления. Это ваша модель приложения (она же модель предметной области) - person Ivo; 13.01.2012
comment
@ivowiblo Модель в MVC — это любая модель данных, которую ваш контроллер подготавливает и передает в представление. Вот почему ваша «модель приложения» (модель предметной области, уровень модели и т. д.) может быть совершенно не подозревая о библиотеках MVC, даже существующих вне вашего решения в отдельно распределенной системе. В MVC запрос просто перенаправляется на контроллер. Контроллер собирает модель представления (данные для уровня представления). Если эта модель является тем же экземпляром объекта, который вы использовали в своей механике постоянства, возможно, это плохая практика, но она разрешена, что означает отсутствие исключительного определения. - person one.beat.consumer; 13.01.2012
comment
+1 за Имейте в виду, что модель в MVC наиболее точно означает модель, о которой знает контроллер, и, следовательно, модель, предназначенную для представления. - person Luiz Damim; 14.09.2012
comment
Этот ответ очень практичен и полезен. Большое спасибо! - person 尤川豪; 30.04.2015

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

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

МВК

Модель Модель может быть любой. Это может быть веб-сервис, ваши репозитории, ваши классы обслуживания или просто ваши модели предметной области. Модель — это все, что используется для получения необходимой информации. Рассматривайте «Модель» как слой, а не как отдельный объект.

Контроллер Контроллер — это связующее звено. Он берет информацию из модели и адаптирует ее к представлению и наоборот.

Вид В представлении должно отображаться только то, что видит пользователь.

Обратите внимание, что не следует путать модель с моделями просмотра. Microsoft действительно должна была назвать папку «Модель» «ViewModels», так как это то, чем они являются. Я бы не стал использовать информацию из "Модели" напрямую в представлениях. Невыполнение этого требования будет означать, что вам придется изменить модель, если изменится представление, и наоборот.

Ответ

Модель - это не модель представления, а слой. Все в модели используется для получения информации, необходимой для представления. Контроллер берет эту информацию и помещает ее в единую модель представления.

Одно действие контроллера может использовать один или несколько вызовов «Модели», чтобы собрать информацию, необходимую для представления.

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

Обратите внимание, что сервисный уровень может не понадобиться. Вы можете вызвать OR/M непосредственно с контроллеров. Но если вы обнаружите, что дублируете код или получаете толстые контроллеры, просто переместите логику на сервисный уровень. Это изменение не повлияет ни на что, кроме контроллера, поскольку вы используете правильные модели представления.

person jgauffin    schedule 12.01.2012
comment
Я бы хотел, чтобы ASP.NET MVC был назван контроллером представления ASP.NET ModelView. Это было бы ужасное имя, но, по крайней мере, оно передало бы его истинный смысл :) - person Hector Correa; 12.01.2012
comment
Даже после использования ASP.NET MVC мне потребовалось некоторое время, чтобы понять, что модель не означает модель представления. - person Lester; 12.01.2012
comment
@one.beat.consumer: Моя точка зрения о модели заключалась в том, что она может быть чем угодно. Это просто слой снаружи. Создайте его так, как он подходит для приложения. Я так выразился, поскольку многие думают, что модель в ASP.NET MVC — это модель представления или что виртуальная машина и модель — это одно и то же. - person jgauffin; 12.01.2012
comment
Я думаю, что я обращаюсь к вопросу. Моя интерпретация customerModel, о которой он говорит в вопросе, - это модель представления. Если он понимает, что это не так, то ответ более очевиден. - person jgauffin; 12.01.2012
comment
Здесь важна семантика @jgauffin - в модели MVC не подразумевается уровень модели; это только подразумевает объект модели, пригодный для того, чтобы Контроллер мог передать его в Представление. В крупных приложениях архитектура MVC часто даже не знает об уровне модели/данных или о том, как вы его называете. Мой отредактированный ответ пытается объяснить эту путаницу... в основном, когда приложения небольшие, часто нет необходимости в дополнительном разделении модели модели и модели представления, поэтому люди, как правило, размечают свои модели и позволяют контроллерам использовать репозиторий и т. д. В полноразмерные приложения, это редко должно происходить. - person one.beat.consumer; 12.01.2012
comment
@jgauffin подумайте об этом - что, если у меня нет настойчивости, и мое приложение просто отправляет электронное письмо, когда кто-то нажимает на действие? В смысле ООП нет уровня модели, только крошечный класс, похожий на DTO (возможно, только строковое сообщение в ViewData/ViewBag), который мое представление отображает для пользователя. Это модель в MVC... она всегда присутствует даже в приложениях со слоем модели - person one.beat.consumer; 12.01.2012
comment
mainly when apps are small, there's often no need for the extra separation of Model and View model. Ну да, еще есть потребность. Без модели представления в представления легко добавить логику для адаптации модели (что приводит к дублированию кода) или ввести риски безопасности, используя модель сущностей непосредственно в представлении. Также: Ничто не говорит о том, что модель является объектом, так что здесь вы не правы. - person jgauffin; 12.01.2012
comment
Существует четкое различие между моделью представления и моделью. Модель — это все, что используется для получения информации. ViewModel создается специально для представления. Это отдельные понятия. ViewModel заимствован из шаблона MVVM. - person jgauffin; 13.01.2012
comment
Моя репутация тут ни при чем. Мои пятнадцать лет работы девелопером и архитектором или университетское образование могут. If an app instantiates a Book class object, persists it somewhere, and returns it to the client in a view, the same exact reference object is performing both roles. нет. Это не модель представления только потому, что вы пытаетесь использовать ее как таковую. Модель представления может преобразовать список книг в IEnumerable<SelectListItem> или вернуть n/a вместо пустой строки для Book.Title. Сущность/модель OR/M не может этого сделать, что вынуждает вас помещать такую ​​логику в представление. - person jgauffin; 13.01.2012
comment
Я не говорю, что это невозможно. Я говорю, что это не настоящая модель представления (en.wikipedia.org/wiki/ View_model#Viewpoint_model). И я говорю, что Модель в MVC — это не отдельная сущность, а все, что используется для получения информации. Отсюда метафора слоя. - person jgauffin; 13.01.2012

Вариант 1: Можно подумать, что модель == сервис. Модель также ЯВЛЯЕТСЯ бизнес-уровнем.

Вариант 2 — это антишаблон модели предметной области Anemic. http://en.wikipedia.org/wiki/Anemic_domain_model

person Imre L    schedule 04.01.2012
comment
Имейте в виду, что для того, чтобы назвать что-то анти-шаблоном, нужен дополнительный контекст! Многим приложениям не нужна модель предметной области, потому что в основном они выполняют операции CRUD. - person Rookian; 24.04.2013
comment
Модель предметной области — это просто данные с метаданными, если у вас нет метаданных, то все в порядке. Я удалил слово против шаблона, потому что в этом вы правы. Мне очень нравится принятый ответ, и мой собственный должен был быть комментарием. - person Imre L; 25.04.2013

Вариант 2 описывается как архитектура Fat Stupid Ugly Controllers (Ссылка на автора этого выражения). Это решение, как правило, противоречит духу MVC, поскольку нарушает разделение задач.

person Sergey Kudriavtsev    schedule 13.01.2012
comment
public ActionResult FetchApple() { return View(_groceryService.GetApple("Granny Smith")); } довольно худой, если вы спросите меня. - person one.beat.consumer; 13.01.2012
comment
Мое прочтение этой статьи FSUC не соответствует варианту 2 выше. В примере, предоставленном автором FSUC, не показано использование сервисного уровня, в котором инкапсулирована вся эта логика упорядочения. Вместо этого он показывает, что контроллер загружен бизнес-логикой. И возможность повторного использования бизнес-логики в силу того, что она находится в контроллере, теперь потеряна. - person Marvo; 14.04.2012