Бог контролеров - как их предотвратить? - PullRequest
15 голосов
/ 21 июня 2009

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

Этот вопрос может быть скорее вопросом «что и куда», но я думаю, что это важный вопрос в отношении SRP (принцип единой ответственности), DRY (не повторяйте себя) и краткости, «гибкости» "- и я недостаточно опытен (с этим шаблоном и общим дизайном), чтобы быть осведомленным об этом.

В одном проекте у нас есть NutritionController. Со временем он стал включать следующие действия (многие с их соответствующими методами GET, POST и DELETE):

Index (home controller)
ViewFoodItem
AddFoodItem
EditFoodItem
DeleteFoodItem
ViewNutritionSummary
SearchFoodItem
AddToFavorites
RemoveFromFavorites
ViewFavorites

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

SearchController {
    SearchExercise
    SearchNutrition
    //... etc
}

FavoritesController {
    ViewNutritionFavorites
    AddToNutritionFavorites
    AddToExerciseFavorites
    EditNutritionFavorites
    EditExerciseFavorites
    //... etc
}

Мне просто кажется, что если вы разделите их на отдельные контроллеры, на каком-то уровне вы вырастите невероятно большую зависимость для работы с информацией, которая вам понадобится. ИЛИ у вас будет полностью универсальное приложение для обработки, которое будет очень трудно обрабатывать, так как вам придется перепрыгивать через множество обручей, чтобы получить желаемый эффект (либо на уровне M, V, либо C).

Я думаю об этом неправильно? Например, должен ли я иметь общий объект Favorites, а затем позволить контроллеру решить, в какое представление его бросить?

* Извините за расшифровку аббревиатур - я делаю это на тот случай, если кто-нибудь еще сталкивается с этим вопросом и не знает, что это за вещи

EDIT: Вся логика, которую я выполняю, в значительной степени обрабатывается на сервисных уровнях. Например, контроллер отправит «новый» FoodItem в сервис. Если он уже существует или произошла ошибка, служба отправит его обратно контроллеру.

Ответы [ 4 ]

12 голосов
/ 21 июня 2009

Я бы разбил ваш первый список на основе ответственности:

HomeController

  • Индекс

FoodItemController

  • ViewFoodItem
  • AddFoodItem
  • EditFoodItem
  • DeleteFoodItem
  • SearchFoodItem

NutritionController

  • ViewNutritionSummary

FavoritesController

  • AddToFavorites
  • RemoveFromFavorites
  • ViewFavorites
  • SearchFavorites

Django * Подход 1050 * к MVC заключается в разделении обязанностей на «приложения», каждое из которых имеет свои собственные модели, контроллеры и даже шаблоны при необходимости. Скорее всего, у вас есть приложение Food, приложение Nutrition, приложение Search и приложение Favorites.

Edit: OP упомянул, что поиск более специфичен для каждого контроллера, поэтому я выполнил эти действия. Тем не менее, поиск также может быть просто глобальной вещью, поэтому в таких случаях SearchController вполне подойдет.

2 голосов
/ 21 июня 2009

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

У меня такое чувство, потому что вы упоминаете о возможности увеличения зависимости вашего контроллера. Хорошо, если FavoritesController необходимо знать о питании и упражнениях (для отображения в том же виде), не ставьте свой контроллер в зависимость от 2-х классов, подобных хранилищу. Вместо этого инкапсулируйте это координационное поведение. Может быть, создать сервис FavoritesService, который знает, как вернуть фавориты и питание, и упражнения. Этот сервис может делегироваться NutritionFabilitiesService и ExerciseFabilitiesService. Таким образом, у вашего контроллера только одна зависимость, вы сохраняете вещи СУХИМЫМИ, применяете SRP и концентрируете свою бизнес-логику в каком-то другом месте, кроме контроллера.

1 голос
/ 02 августа 2010

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

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

Другими словами, если действие не относится ни к одному из действий Index, New, Create, Show, Edit, Update и Destroy, тогда я добавляю новый контроллер, специфичный для требуемого действия.

Для вашего примера.

SearchController {
    SearchExercise
    SearchNutrition
    //... etc
}

Я бы реорганизовал это в ...

   SearchExerciseController {
           Index   
   }

   SearchNutritionController {
           Index   
   }

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

Например. Выполняет ли действие SearchExercise представление View для поиска упражнения или оно действительно выполняет поиск? Вы, вероятно, можете убедиться в этом, посмотрев на параметры и тело, но это не так просто, как, например, пара действий Создать и Создать или Изменить и Обновить.

SearchController {
    SearchExercise       
}
1 голос
/ 21 июня 2009

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

...