15

En algunos proyectos MVC que he estado trabajando, se ha hecho evidente que hay algunos controladores problemáticos que han crecido orgánicamente en clases Dios - semidioses cada uno en su propio dominio, si se quiere.God Controllers - ¿Cómo prevenirlos?

Esta pregunta podría ser más una cuestión 'qué va donde,' pero creo que es una pregunta importante con respecto a SRP (Principio de Responsabilidad Individual), DRY (Do not Repeat Yourself), y mantener las cosas concisas, " ágil "- y no tengo suficiente experiencia (con este patrón y en el diseño general) para estar bien informado sobre esto.

En un proyecto, tenemos un NutritionController. Con el tiempo ha crecido para incluir estas acciones (muchas de ellas con su respectivo, GET, POST y DELETE métodos):

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

Entonces tenemos un ExerciseController, que incluirá muchas acciones similares, como la búsquedas y acciones favoritas. ¿Deberían refactorizarse en su propio controlador para que sea algo así?

SearchController { 
    SearchExercise 
    SearchNutrition 
    //... etc 
} 

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

apenas se parece a mí que si se rompe hacia fuera en controladores separados, vas a crecer una dependencia increíblemente grande en algún nivel para hacer frente a la información que se necesita. O va a tener una aplicación de manejo completamente genérica que será muy difícil de manejar, ya que tendrá que pasar por tantos aros para obtener el efecto deseado (ya sea en el nivel M, V o C).

estoy pensando en esto a mal? Por ejemplo, ¿debería tener un objeto genérico de Favoritos y luego dejar que el controlador decida a qué vista lanzarlo?

* Lo siento por deletreando las siglas - que estoy haciendo lo que en caso de que alguien más viene a través de esta pregunta y no tiene ni idea de lo que esas cosas son

EDIT: Toda la lógica es que realizo prácticamente manejado en las capas de servicio. Por ejemplo, el controlador enviará el 'nuevo' FoodItem al servicio. Si ya existe, o hay un error con él, el servicio lo enviará nuevamente al controlador.

Respuesta

12

Me gustaría romper su primera lista hasta basada en la responsabilidad:

HomeController

  • Índice

FoodItemController

  • ViewFoodItem
  • AddFoodItem
  • EditFoodItem
  • DeleteFoodItem
  • SearchFoodItem

NutritionController

  • ViewNutritionSummary

FavoritesController

  • AddToFavorites
  • RemoveFromFavorites
  • ViewFavorites
  • SearchFavorites
  • enfoque

Django 's para MVC es separar las responsabilidades en "aplicaciones", cada uno con sus propios modelos , controladores e incluso plantillas si es necesario. Es probable que tenga una aplicación de Alimentos, una aplicación de Nutrición, una aplicación de Búsqueda y una aplicación de Favoritos.

Editar: El OP mencionó que la búsqueda es más específica para cada controlador, por lo que he hecho esas acciones. Sin embargo, la búsqueda también puede ser solo general, por lo que en esos casos, un SearchController estaría bien.

+0

Entonces, ¿repetiría las mismas cosas para los ejercicios o las agregaría a esos controladores? ES DECIR. ¿manejaría SearchController los métodos SearchExerciseItem, o sería otro controlador como SearchExerciseController? – MunkiPhD

+0

Si así es como lo tiene configurado, la búsqueda es una acción en el controlador, no un controlador en este punto. Si la búsqueda fuera algo general, entonces podría ser su propio controlador. He modificado mi respuesta para reflejar esto. – Soviut

+0

MVC trabaja con REST de forma muy natural: todos sus controladores "controlan" un único tipo de recurso y saben cómo realizar diversas acciones en ese recurso (es decir, responder a varios mensajes pasados ​​a ese recurso), con asignación de clases de recursos REST. a los tipos de entidad de modelo de dominio principalmente uno a uno (ese es el punto de tener un modelo de dominio). – yfeldblum

1

No estoy muy familiarizado con ese marco, pero puedo ofrecer algunos consejos generales. Un controlador probablemente solo sepa cómo completar una sola acción o invocar a otros controladores de acción única para completar una secuencia de acciones relacionadas. Cualquier información que deba pasarse de la acción a la acción probablemente deba pasarse de algún modo a través de la capa del modelo, ya que esa información probablemente sea relevante para el modelo subyacente.

+2

Así no funciona en muchos frameworks MVC (por ejemplo, Rails, ASP.NET MVC). Un único controlador sabe cómo realizar muchas acciones en un solo tipo de entidad, pero no debe saber cómo realizar acciones en otros tipos de entidades. – yfeldblum

2

Do as Soviut says. Desea mantener los controladores simples. Parece que terminas con demasiada lógica de coordinación en tus controladores. Recuerde que son responsables de conectar una vista y un modelo. Esta lógica de coordinación probablemente debería dividirse en servicios.

Tengo esta sensación porque menciona la posibilidad de que su controlador genere enormes dependencias. Bueno, si FavoritesController necesita saber acerca de la nutrición y los favoritos de ejercicio (para mostrar en la misma vista) no haga que su controlador dependa de 2 depósitos como clases. En cambio, encapsula ese comportamiento de coordinación. Tal vez cree un servicio de favoritos que sepa cómo devolver los favoritos de nutrición y ejercicio. Ese servicio podría delegar en NutritionFavoritesService y ExerciseFavoritesService.De esta forma su controlador solo termina con 1 dependencia, mantiene las cosas SECAS, aplicando el SRP y concentrando su lógica comercial en algún lugar que no sea el controlador.

+0

Tengo la mayor parte de la lógica de coordinación en los servicios, pero parece como si tuviera métodos muy específicos tanto en mis controladores como en las capas de servicio. Por ejemplo, el controlador tendrá la llamada 'GetFavoriteFoodItemsForUser' a la capa de servicio donde manejo todo y devuelvo una lista, que luego el controlador vuelca a una vista. – MunkiPhD

+0

Ah. Trataré de presentar algunas reglas generales y actualizar mi respuesta. Para el ejemplo que proporcionaste, probablemente tendría un UserController con un método FavoirteFoodTiems que solo acepta HttpMetthod GET. –

+0

Su edición ha aclarado un poco para mí - Gracias – MunkiPhD

1

También he experimentado este tipo de dolores de cabeza por mantenimiento y me apegaba a un método tipo "Rails" para ser muy útil a la hora de mantener mis controles enfocados y sin marcar.

Si me encuentro agregando acciones con nombres inusuales, por ejemplo. Para usar un ejemplo de blogging, AddPostToBlog, eso sería una bandera para crear un nuevo controlador Post con una acción Crear.

En otras palabras, si la acción no es una de las acciones Indizar, Nuevo, Crear, Mostrar, Editar, Actualizar y Destruir, entonces agrego un nuevo controlador específico para la acción que requiero.

Para su ejemplo.

SearchController { 
    SearchExercise 
    SearchNutrition 
    //... etc 
} 

Me refactorizar esto ...

SearchExerciseController { 
      Index 
    } 

    SearchNutritionController { 
      Index 
    } 

Esto puede significar tener más controladores, pero en mi opinión eso es más fácil de manejar que cada vez más amplio controladores "dios". También significa que los controladores son más auto documentados.

Por ejemplo. ¿La acción SearchSpecer, devuelve la vista para buscar el ejercicio o realiza la búsqueda? Probablemente pueda determinar esto mirando los parámetros y el cuerpo, pero no es tan fácil como, por ejemplo, un par de acciones Nuevo y Crear, o Editar y Actualizar.

SearchController { 
    SearchExercise  
} 
Cuestiones relacionadas