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

84

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

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

Вариант 1 - Модель разговаривает со службами

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

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

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

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

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

Питер из Кельна
источник

Ответы:

95

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

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

  1. Экономичное моделирование домена

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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


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

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


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

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

one.beat.consumer
источник
11
Это почти тот же шаблон проектирования, который я использую, за исключением того, что контроллер не знает репозитория. Контроллер взаимодействует только с сервисами, которые, в свою очередь, взаимодействуют с репозиториями.
Лестер
2
@Lester Я отредактировал, чтобы прояснить это. В 95% случаев мой тоже этого не делает, идея в том, что сервисы делают. В небольших приложениях это может быть излишним, но это хорошая практика для всех, и намного проще поддерживать с контейнером IoC
one.beat.consumer
1
+1 @ one.beat.consumer: это тот же подход, который я использую в своих проектах ... иногда слишком пуристический подход к правилам приводит к слишком сложным решениям, и вы можете получить больше преимуществ от проверенного в реальном мире решения, которое не идеально следует шаблонам
GOF
7
Модель @ivowiblo в MVC - это любая модель данных, которую ваш контроллер подготавливает и передает в представление. Вот почему ваша «модель приложения» (модель предметной области, уровень модели, все, что вы называете) может совершенно не знать о библиотеках MVC, даже существовать вне вашего решения в отдельно распределенной системе. В MVC запрос просто направляется контроллеру. Контроллер собирает модель представления (данные для уровня представления). Если эта модель такой же , проиллюстрированный объект , который вы использовали в вашей механике настойчивости, плохой практике , может быть, но это будет разрешено, то есть не исключительное определение.
one.beat.consumer
2
+1 для Помните, что «Модель» в MVC наиболее точно означает модель, о которой знает Контроллер, и, следовательно, модель, предназначенную для представления.
Луис Дамим
16

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

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

MVC

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

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

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

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

Ответ

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

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

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

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

Джгауффин
источник
3
Я бы хотел, чтобы ASP.NET MVC был назван контроллером представления ASP.NET ModelView. Это было бы ужасное имя, но, по крайней мере, оно передало бы его истинное значение :)
Гектор Корреа
Мне потребовалось некоторое время, даже после использования ASP.NET MVC, чтобы понять, что эта модель не означает модель представления.
Лестер
@ one.beat.consumer: Я хотел сказать о Модели, что это может быть что угодно. Это просто слой снаружи. Создайте его так, как он подходит для приложения. Я так выразился, поскольку многие думают, что Модель в ASP.NET MVC - это модель представления или что виртуальная машина и модель - это одно и то же.
jgauffin
Думаю, что обращаюсь к этому вопросу. Моя интерпретация того, о customerModelчем он говорит в вопросе, - это модель представления. Если он поймет, что это не так, ответ более очевиден.
jgauffin
2
Здесь важна семантика @jgauffin - в MVC «модель» не подразумевает «уровень модели»; он подразумевает только объект модели, пригодный для передачи Контроллером в представление . В масштабных приложениях архитектура MVC часто даже не знает об уровне модели / данных или о том, как вы его называете. Мой отредактированный ответ пытается объяснить эту путаницу ... в основном, когда приложения небольшие, часто нет необходимости в дополнительном разделении модели модели и модели представления, поэтому люди склонны размечать свои модели и позволять контроллерам использовать репозиторий и т. Д. полноразмерные приложения, такое случается редко.
one.beat.consumer
0

Вариант 1: вы могли подумать, что model == service. Модель также является бизнес-уровнем.

Вариант 2 - это антипаттерн модели анемического домена. http://en.wikipedia.org/wiki/Anemic_domain_model

Имре Л
источник
Имейте в виду, что для того, чтобы называть что-то антипаттерном, нужен дополнительный контекст! Многим приложениям не нужна модель предметной области, потому что они в основном выполняют операции CRUD.
Rookian
Модель домена - это просто данные с «метаданными», если у вас нет метаданных, тогда хорошо. Я удалил слово «антипаттерн», потому что вы правы в этом вопросе. Мне действительно нравится принятый ответ, и вместо этого следовало бы прокомментировать мой собственный.
Imre L
0

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

Сергей Кудрявцев
источник
1
public ActionResult FetchApple() { return View(_groceryService.GetApple("Granny Smith")); }довольно худощав, если вы спросите меня.
one.beat.consumer
4
Мое прочтение статьи FSUC не соответствует варианту 2 выше. В примере, предоставленном автором FSUC, не показано использование уровня обслуживания, в котором инкапсулирована вся логика упорядочивания. Вместо этого он показывает, что в контроллер загружена бизнес-логика. А возможность повторного использования бизнес-логики, поскольку она находится в контроллере, теперь потеряна.
Марво,