Используйте сервисный уровень с MVC

13

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

  • Если я просто оберну логику внутри класса сервиса, я получу кучу сервисов с одним / двумя методами. Это похоже на запах кода. Какие-либо лучшие практики в этом отношении?

  • Может ли сервис создавать экземпляры моделей?

  • Если служба создает экземпляры моделей, они не могут быть протестированы модулем. Они могут быть покрыты только интеграционными тестами?

danidacar
источник

Ответы:

25

В «SOLID» «I» обозначает разделение интерфейса. Вся идея этого принципа состоит в том, чтобы разделить большие интерфейсы на более мелкие, более модульные. В MVC сервис обычно имеет интерфейс, на который будет полагаться контроллер. Вы не хотите, чтобы ваши контролеры знали о конкретной реализации этого сервиса. Следовательно, полезно иметь несколько сервисов с одним или двумя методами.

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

  • Контроллер звонит в сервис
  • Сервис возвращает объект (будь то DTO, модель домена или что-то еще)
  • Контроллер отображает модель DTO / домена в модель представления

Сопоставление может быть выполнено вручную, но большинство разработчиков предпочитают использовать среду автоматического сопоставления, такую ​​как Automapper, потому что нам не нравится писать программный код, и мы можем быть довольно ленивыми :-)

http://en.wikipedia.org/wiki/Interface_segregation_principle

https://github.com/AutoMapper/AutoMapper

Одно из многих обсуждений стекопотока, касающихся использования DTO и моделей доменов: /programming/2680071/dto-or-domain-model-object-in-the-view-layer

CodeART
источник
1
Я был бы осторожен при использовании автоматического картографа здесь uglybugger.org/software/post/…
Даниэль Литтл
AutoMapper поставляется со встроенной функциональностью модульного тестирования, которая позволяет вам проверять все ваши процедуры отображения одной строкой. Автор этого поста не упомянул об этом.
CodeART
Но он знает об этом и использовал это. Комментарии идут в это немного.
Даниэль Литтл
2
Многие классы с одним или двумя методами обычно означают, что они не связаны между собой. Уровень обслуживания, если он существует, должен быть тонким, так как основная часть логики находится в моделях. Кажется довольно бессмысленным привязывать взгляд к тупому объекту, который является не чем иным, как сумкой свойств. Модель в MVC должна быть моделью с богатым доменом, а не анемичной. Martinfowler.com/bliki/AnemicDomainModel.html
Энди
3

В MVC Модель - это не просто DTO или набор Менеджеров / Сервисов, она предназначена для представления концепций, которые моделирует ваше приложение. Вы можете думать об этом как о целой области или бизнес-логике, включая состояние и поведение. Теперь, учитывая, что мы знаем, что назначение контроллера становится немного понятнее. Его задача - просто переводить команды в модель и результат обратно в представления. Обычно это делается в виде ViewModels, которые отличаются, но часто путают с моделью в MVC.

Если у вас нет четко определенной Модели, то вы, возможно, дошли до того, что большая часть этой логики теперь находится в самих контроллерах. На данный момент, чтобы начать уменьшать размер ваших контроллеров, вы можете начать перетягивать эту логику обратно в объекты менеджера или службы. Эти сервисы обычно возвращают и работают с объектами типа DTO / Entity. Затем контроллер становится уровнем отображения между этими службами и моделями представления. Несколько хороших советов по составлению карт можно найти в этой статье. Друзья не позволяют друзьям использовать AutoMapper .

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

Даниэль Литтл
источник
3

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

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

Попробуйте подчиниться модели model-view-controller как показано ниже:

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

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

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

просто говорю йо ....

Fredylg
источник
1
Если ваша модель просто dto, вы попали в модель анемичного домена antipattern martinfowler.com/bliki/AnemicDomainModel.html
Энди