El Principio de Responsabilidad Única establece que "una clase debería tener una razón para el cambio".
En el patrón MVC, el trabajo del controlador es mediar entre la vista y el modelo. Ofrece una interfaz para que la Vista informe acciones realizadas por el usuario en la GUI (por ejemplo, permitiendo que la Vista llame controller.specificButtonPressed()
), y puede llamar a los métodos apropiados en el Modelo para manipular sus datos o invocar sus operaciones (por ejemplo model.doSomething()
) .
Esto significa que:
- El Controlador necesita saber acerca de la GUI para poder ofrecer a la Vista una interfaz adecuada para informar sobre las acciones del usuario.
- También necesita saber acerca de la lógica en el Modelo, para poder invocar los métodos apropiados en el Modelo.
Eso significa que tiene dos razones para cambiar : un cambio en la GUI y un cambio en la lógica de negocios.
Si la GUI cambia, por ejemplo, se agrega un nuevo botón, el Controlador podría necesitar agregar un nuevo método para permitir que la Vista informe que un usuario presiona este botón.
Y si la lógica de negocios en el Modelo cambia, el Controlador podría tener que cambiar para invocar los métodos correctos en el Modelo.
Por lo tanto, el controlador tiene dos posibles razones para cambiar . ¿Rompe SRP?
fuente
Respuestas:
Si continúa razonando sobre el SRP, notará que "responsabilidad única" es en realidad un término esponjoso. Nuestro cerebro humano es de alguna manera capaz de distinguir entre diferentes responsabilidades y múltiples responsabilidades pueden resumirse en una responsabilidad "general". Por ejemplo, imagine que en una familia común de 4 personas hay un miembro de la familia responsable de preparar el desayuno. Ahora, para hacer esto, uno tiene que hervir huevos y tostar pan y, por supuesto, preparar una taza saludable de té verde (sí, el té verde es lo mejor). De esta forma, puede dividir "preparar el desayuno" en trozos más pequeños que se resumen juntos en "preparar el desayuno". Tenga en cuenta que cada pieza también es una responsabilidad que, por ejemplo, podría delegarse a otra persona.
Volviendo al MVC: si la mediación entre el modelo y la vista no es una responsabilidad sino dos, entonces, ¿cuál sería la siguiente capa de abstracción anterior, combinando esas dos? Si no puede encontrar uno, no lo resumió correctamente o no hay ninguno, lo que significa que lo hizo bien. Y creo que ese es el caso con un controlador, que maneja una vista y un modelo.
fuente
Si una clase tiene "dos posibles razones para cambiar", entonces sí, viola SRP.
Un controlador generalmente debe ser liviano y tener la responsabilidad única de manipular el dominio / modelo en respuesta a algún evento guiado por GUI. Podemos considerar que cada una de estas manipulaciones son básicamente casos de uso o características.
Si se agrega un nuevo botón en la GUI, el controlador solo debería cambiar si ese nuevo botón representa alguna función nueva (es decir, opuesta al mismo botón que existía en la pantalla 1 pero que aún no existía en la pantalla 2, y es entonces agregado a la pantalla 2). Tendría que haber un nuevo cambio correspondiente en el modelo también, para admitir esta nueva funcionalidad / característica. El controlador todavía tiene la responsabilidad de manipular el dominio / modelo en respuesta a algún evento impulsado por GUI.
Si la lógica de negocios en el modelo cambia debido a que se solucionó un error y requiere que el controlador cambie, entonces este es un caso especial (o tal vez el modelo está violando el principal abierto-cerrado). Si la lógica de negocios en el modelo cambia para admitir alguna funcionalidad / característica nueva, entonces eso no necesariamente afecta al controlador, solo si el controlador necesita exponer esa característica (que casi siempre sería el caso, de lo contrario, ¿por qué se agregaría a el modelo de dominio si no se usará). Entonces, en este caso, el controlador también debe modificarse, para admitir la manipulación del modelo de dominio de esta nueva forma en respuesta a algún evento impulsado por GUI.
Si el controlador tiene que cambiar porque, por ejemplo, la capa de persistencia se cambia de un archivo plano a una base de datos, entonces el controlador ciertamente está violando SRP. Si el controlador siempre funciona en la misma capa de abstracción, eso puede ayudar a lograr SRP.
fuente
El controlador no viola SRP. Como usted dice, su responsabilidad es mediar entre los modelos y la vista.
Dicho esto, el problema con su ejemplo es que está vinculando los métodos de controlador a la lógica en la vista, es decir
controller.specificButtonPressed
. Nombrar los métodos de esta manera vincula el controlador a su GUI, no ha podido abstraer correctamente las cosas. El controlador debe tratar de realizar acciones específicas, es decir,controller.saveData
ocontroller.retrieveEntry
. Agregar un nuevo botón en la GUI no significa necesariamente agregar un nuevo método al controlador.Al presionar un botón en la vista, significa hacer algo, pero lo que sea que se haya hecho podría haberse activado fácilmente de cualquier otra manera o incluso a través de la vista.
Del artículo de Wikipedia sobre SRP
El controlador no se preocupa por lo que está en la vista solo que cuando se llama a uno de sus métodos, proporciona datos específicos a la vista. Solo necesita saber acerca de la funcionalidad del modelo en la medida en que sepa que necesita llamar a los métodos que tendrán. No sabe nada más que eso.
Saber que un objeto tiene un método disponible para llamar no es lo mismo que conocer su funcionalidad.
fuente
specificButtonsPressed()
es porque leí que la vista no debería saber nada sobre la funcionalidad de sus botones y otros elementos de la GUI. Me han enseñado que cuando se presiona un botón, la vista simplemente debe informar al controlador, y el controlador debe decidir "qué significa" (y luego invocar los métodos apropiados en el modelo). Hacer la llamada de vistacontroller.saveData()
significa que la vista tiene que saber qué significa presionar este botón, además del hecho de que se presionó.specificButtonPressed()
), de hecho, el controlador no estaría tan vinculado a la GUI. ¿Debo abandonar losspecificButtonPressed()
métodos? ¿La ventaja que creo que tiene estos métodos tiene sentido para usted? ¿ObuttonPressed()
no vale la pena tener métodos en el controlador?specificButtonPressed()
métodos en el controlador es que separa la Vista del significado de presionar completamente los botones . Sin embargo, la desventaja es que vincula el controlador a la GUI en cierto sentido. ¿Qué enfoque es mejor?foo
, o con la misma facilidadfireZeMissiles
. Solo sabrá que debe informar a una función específica. No sabe qué hace la función, solo eso lo llamará. El controlador no está preocupado por cómo se invocan sus métodos, solo porque responderá de cierta manera cuando lo estén.La responsabilidad única de los controladores es ser el contrato que media entre la vista y el modelo. La vista solo debe ser responsable de la pantalla, el modelo solo debe ser responsable de la lógica empresarial. Es responsabilidad de los controladores unir esas dos responsabilidades.
Eso está muy bien, pero alejarse un poco de la academia; un controlador en MVC generalmente se compone de muchos métodos de acción más pequeños. Estas acciones generalmente corresponden a cosas que una cosa puede hacer. Si vendo productos, probablemente tendré un ProductController. Ese controlador tendrá acciones como GetReviews, ShowSpecs, AddToCart ect ...
La vista tiene el SRP de mostrar la interfaz de usuario, y parte de esa interfaz de usuario incluye un botón que dice AddToCart.
El controlador tiene el SRP de conocer todas las vistas y modelos involucrados en el proceso.
La acción AddToCart de los controladores tiene el SRP específico de conocer a todos los que deben participar cuando se agrega un artículo a un carrito.
El modelo del producto tiene el SRP de modelar la lógica del producto, y el modelo ShoppingCart tiene el SRP de modelar cómo se guardan los artículos para su posterior pago. El modelo de usuario tiene un SRP de modelado del usuario que agrega cosas a su carrito.
Puede y debe reutilizar modelos para hacer su negocio y esos modelos deben estar acoplados en algún momento de su código. El controlador controla cada forma única en que ocurre el acoplamiento.
fuente
Los controladores en realidad solo tienen una responsabilidad: alterar el estado de las aplicaciones en función de la entrada del usuario.
source: wikipedia
Si, en cambio, tiene "controladores" al estilo Rails (que hacen malabarismos con instancias de registro activas y plantillas tontas) , entonces, por supuesto, están rompiendo SRP.
Por otra parte, las aplicaciones de estilo Rails no son realmente MVC para empezar.
fuente