¿Es realmente necesaria la 'C' en MVC?

38

Entiendo el papel del modelo y la vista en el patrón Modelo-Vista-Controlador, pero me cuesta entender por qué es necesario un controlador.

Supongamos que estamos creando un programa de ajedrez utilizando un enfoque MVC; el estado del juego debería ser el modelo, y la GUI debería ser la vista. ¿Qué es exactamente el controlador en este caso?

¿Es solo una clase separada que tiene todas las funciones que se llamarán cuando, por ejemplo, haga clic en un mosaico? ¿Por qué no simplemente realizar toda la lógica en el modelo en la vista misma?

Anne Nonimus
fuente
1
Personalmente, esto es lo que hago . Puede haber casos en los que no hay alternativa a MVC, pero no lo soporto.
Mike Dunlavey
10
Tres palabras ... "Separación de preocupaciones".
Travis J
44
Casi todos los programas de Windows anteriores a .net usaban Doc-View sin controlador. Esto parece haber sido relativamente exitoso.
Martin Beckett
Martin, monolitos imposibles (cambiantes).
Independiente el
He respondido a continuación, pero agregaré que sí, puede crear una aplicación sin clases de controlador distintas, pero eso no sería MVC. Estás asumiendo "un enfoque MVC", así que sí, los controladores juegan un papel importante. Si elige algún paradigma que no sea MVC, es muy posible que no tenga ningún controlador.
Caleb

Respuestas:

4

Usando su ejemplo, el Controlador sería lo que decidía qué era un movimiento legal o no. El Controlador le permitiría a la vista saber cómo organizar las piezas en el tablero al inicio utilizando la información que recibió del Modelo. El controlador puede manejar más cosas, pero la clave es pensar en Business Logic en esa capa.

Hay momentos en que todo lo que hace el controlador es pasar información de un lado a otro, como una página de registro. Otras veces, el controlador es la parte difícil del desarrollo porque hay muchas cosas que deben hacerse en esa capa, como hacer cumplir las reglas o hacer matemáticas complicadas, por ejemplo. ¡No te olvides del controlador!

JustinDoesWork
fuente
36
"Usando su ejemplo, el Controlador sería lo que decidía qué era un movimiento legal o no". Este es un mal ejemplo :( dicha lógica también estará en el Modelo. De lo contrario, su lógica se dividirá entre el Controlador y el Modelo.
Dime
66
@Dime: el modelo no debe contener lógica alguna. El controlador será el que tenga la lógica, por lo tanto, "controlará".
Travis J
34
@TravisJ No estoy muy de acuerdo allí. Controlar no significa saber hacer un trabajo. Se trata de controlar esos objetos que lo hacen. Por lo tanto, la lógica para hacer el trabajo estaría en el modelo y el controlador controlaría qué modelo usar para realizar los requisitos necesarios de la acción, etc. Demasiada lógica en los controladores, en mi opinión, sería la receta para la transferencia del controlador ...
dreza
25
El objetivo de OOP es tener bits cohesivos de datos y comportamiento que se mantengan unidos y encapsulados internamente. El "modelo" modela tanto el comportamiento como los datos.
Misko
12
-1 El controlador no debe contener lógica empresarial. El modelo es "la aplicación", contiene los datos y tiene rutinas invocables para todo lo que puede suceder en la aplicación; no necesariamente todo en un archivo o clase. La vista visualiza el estado del modelo. El controlador une el modelo / vista y el mundo real / entrada. ¿Quiere "publicar" la aplicación como una aplicación web? Solo necesito un controlador que maneje HTTP y una vista adecuada basada en HTML. ¿Quieres una interfaz de línea de comandos para tu aplicación? Solo necesito un controlador y una vista apropiados. El modelo, la lógica de negocios, nunca cambia en estos casos.
deceze
39

¿Por qué no simplemente realizar toda la lógica en el modelo en la vista misma?

El controlador es el pegamento que une el modelo y la vista, y también es el aislamiento que los mantiene separados. El modelo no debería saber nada sobre la vista y viceversa (al menos en la versión de Apple de MVC). El controlador actúa como un adaptador de dos vías, traduciendo las acciones del usuario de la vista en mensajes al modelo y configurando la vista con datos del modelo.

El uso del controlador para separar el modelo y la vista hace que su código sea más reutilizable, más comprobable y más flexible. Considera tu ejemplo de ajedrez. Por supuesto, el modelo incluiría el estado del juego, pero también podría contener la lógica que afecta los cambios en el estado del juego, como determinar si un movimiento es legal y decidir cuándo termina el juego. La vista muestra un tablero de ajedrez y piezas y envía mensajes cuando una pieza se mueve, pero no sabe nada sobre el significado detrás de las piezas, cómo se mueve cada pieza, etc. El controlador conoce tanto el modelo como la vista, así como El flujo general del programa. Cuando el usuario presiona el botón 'nuevo juego', es un controlador que le dice al modelo que cree un juego y usa el estado del nuevo juego para configurar el tablero. Si el usuario hace un movimiento,

Mira lo que obtienes al mantener el modelo y ver por separado:

  • Puede cambiar el modelo o la vista sin cambiar el otro. Puede que tenga que actualizar el controlador cuando cambie cualquiera de los dos, pero de alguna manera esto es parte de la ventaja: las partes del programa que tienen más probabilidades de cambiar se concentran en el controlador.

  • El modelo y la vista se pueden reutilizar. Por ejemplo, podría usar la misma vista de tablero de ajedrez con un feed RSS como modelo para ilustrar juegos famosos. O bien, puede usar el mismo modelo y reemplazar la vista con una interfaz basada en la web.

  • Es fácil escribir pruebas tanto para el modelo como para la vista para garantizar que funcionen como deberían.

  • Tanto el modelo como la vista a menudo pueden aprovechar las partes estándar: matrices, mapas, conjuntos, cadenas y otros contenedores de datos para el modelo; botones, controles, campos de texto, vistas de imágenes, tablas y otros para la vista.

Caleb
fuente
1
En la arquitectura MVC original para aplicaciones de escritorio, las vistas eran clases activas, observaban el modelo directamente y se desconectaban del controlador.
Kevin Cline
El problema con todas las respuestas es que hay tantas interpretaciones de MVC como personas publicando. Y los beneficios enumerados anteriormente solo se aplican a una interpretación específica de MVC. Si uno pusiera la mayor parte de la lógica en el controlador (o modelo) y tuviera la llamada Ver / iniciar llamadas a métodos específicos en el controlador, entonces eso hace que el combo Controlador / Modelo sea independiente y muy reutilizable. La mayoría de las veces se necesita una nueva vista. Nunca he tenido la necesidad de reutilizar una vista. Incluso su ejemplo RSS podría manejarse fácilmente con una nueva Vista que usa la anterior con una capa RSS en el medio.
Dunk
2
@Dunk: es vital separar la lógica empresarial de la interfaz de usuario para que la lógica empresarial se pueda probar directamente.
Kevin Cline
@Kevin: Estoy totalmente de acuerdo, la lógica de negocios no pertenece a la interfaz de usuario. Sin embargo, el controlador no necesita ser parte de la interfaz de usuario. A eso me refiero con que hay muchas definiciones. En la definición de una persona, el controlador maneja las pulsaciones de los botones, mientras que otra persona lo colocará como parte de la vista. Si la vista sabe cómo convertir las acciones del operador (es decir, presionar botones / selecciones de elementos) en solicitudes de aplicaciones, entonces el Controlador / Modelo se vuelve muy reutilizable con casi cualquier tipo de interfaz de usuario, que podría incluir interfaces GUI, Consolas o redes.
Dunk
1
@Dunk: supongo que puede llamar a cualquier cosa que desee como "controlador", pero en la arquitectura MVC, el controlador depende y, por lo tanto, es parte de la interfaz de usuario.
Kevin Cline
7

Hay muchas, muchas formas diferentes de implementar este patrón de diseño general, pero la idea básica es separar las diversas preocupaciones según sea necesario. MVC es una buena abstracción en el sentido de que:

Modelo : Representa esos datos, lo que sea que eso signifique
Vista : Representa la interfaz de usuario, lo que sea que eso signifique
Controlador : Representa el pegamento que hace que ese modelo y vista interactúen, lo que sea que eso signifique

Es extremadamente flexible porque no especifica mucho. Mucha gente desperdicia una gran cantidad de ancho de banda discutiendo los detalles de lo que cada elemento podría significar, qué nombres deberían usarse en lugar de estos, y si realmente debería haber 3 o 2 o 4 o 5 componentes, pero ese es el punto que falta a Cierto grado.

La idea es separar los diferentes "fragmentos" de lógica para que no se superpongan. Mantenga sus elementos de presentación juntos, sus elementos de datos juntos, sus elementos lógicos juntos, sus elementos de comunicación juntos. Etcétera. Hasta cierto punto, cuanto menos se superpongan estas áreas de preocupación, más fácil será hacer cosas interesantes con ellas.

Eso es todo de lo que realmente debería preocuparse.

tylerl
fuente
3
Pegamento, pegamento, me gusta esa definición, es tan correcta: todo el modelo debería ser bautizado como MVG y la gente dejaría de rascarse la cabeza en busca de elegancia donde no hay nada que encontrar.
ZJR
1
+1 para "pegamento"; También significa que es la parte que mejor se adapta a un lenguaje de secuencias de comandos (ya que tienden a sobresalir en el pegado).
Donal Fellows
@DonalFellows Me gusta mucho ese pensamiento. Algo que "pega" 2 entidades dispares juntas necesita mucha flexibilidad que promueven los lenguajes de script débilmente escritos (es decir, JavaScript)
Zack Macomber
4

Todas buenas respuestas hasta ahora. Mis dos centavos es que me gusta pensar que el controlador está construido principalmente con preguntas como ¿Qué y dónde?

  • Me preguntaron si una pieza de ajedrez (vista) se puede mover a x. ¿Está
    permitido? No estoy seguro, pero sé dónde y a quién preguntar (el modelo).
  • Algo me ha pedido que guarde mis datos. ¿Cómo diablos hago eso? ¡Aunque sé dónde preguntar! Cómo guardamos los datos, o dónde se guardan, no tengo idea, pero esa clase de repositorio debería saberlo. Lo reenviaré y dejaré que se ocupe de eso.
  • Tengo que mostrarle al usuario la posición actual de la pieza de ajedrez a la que la movió el modelo. ¿No estoy seguro si quiero mostrar la pieza como verde o amarilla? Bah, a quién le importa, sé que hay una vista que puede manejar esto, así que les pasaré los datos y ellos podrán decidir cómo se mostrarán.

Estos pequeños fragmentos son ejemplos de cómo estoy tratando de recordar la abstracción y el concepto que MVC está tratando de transmitir. Qué, dónde y cómo son mis tres procesos de pensamiento principales.

Qué y dónde => Controlador Cómo y cuándo => Modelos y vistas

En esencia, mis acciones de controlador tienden a ser pequeñas y compactas y, al leerlas, a veces parecen una pérdida de tiempo. En una inspección más cercana, están actuando como el hombre de la señal de tráfico, canalizando las diversas solicitudes a los trabajadores apropiados, pero no realizan ninguno de los trabajos en sí.

dreza
fuente
2

Un controlador podría ayudar a abstraer las interfaces tanto de la vista como del modelo para que no tengan que conocerse directamente. Cuanto menos debe saber un objeto, más portátil y comprobable por unidad se vuelve.

Por ejemplo, el Modelo podría estar jugando otra instancia de sí mismo a través de un Controlador. O un controlador en red podría conectar los objetos Vistas de dos jugadores juntos. O podría ser una prueba de Turing donde nadie sabe cuál.

hotpaw2
fuente
2

Realmente entra en juego cuando se trata de controladores de eventos, pero aún necesita el controlador para manejar las interacciones entre la vista y el modelo. Idealmente, no desea que la vista sepa nada sobre el modelo. Piénselo, ¿quiere un jsp para hacer todas las llamadas a la base de datos directamente? (A menos que sea algo así como una búsqueda de inicio de sesión). Desea que la vista muestre datos y no tenga ninguna lógica empresarial, a menos que sea una lógica de visualización, pero no una lógica empresarial perse.

En GWT, obtienes una separación más limpia con MVP. No hay lógica de negocios en absoluto (si se hace correctamente) en la vista. El presentador actúa como controlador y la vista no tiene conocimiento del modelo. Los datos del modelo simplemente se pasan a la vista.


fuente
1

Document-View (es decir, vista de modelo) es el modelo estándar para la mayoría de las aplicaciones de Windows escritas en MFC, por lo que debe funcionar en muchos casos.

Martin Beckett
fuente
1

Entiendo el papel del modelo y la vista en el patrón Modelo-Vista-Controlador, pero me cuesta entender por qué es necesario un controlador.

¿Está seguro de eso? (Al menos como se describió originalmente) El objetivo del modelo es ser el modelo de dominio. Se supone que la vista muestra el modelo de dominio al usuario. Se supone que el controlador asigna la entrada de bajo nivel al modelo de alto nivel. Por lo que puedo decir, el razonamiento es algo similar a: A) un uso de alto nivel del SRP. B) Se consideró que el modelo era la parte importante de la aplicación, así que mantén las cosas sin importancia y que cambien más rápido. C) lógica empresarial fácilmente comprobable (y capaz de guion).

Solo piense si quiere hacer que su programa de ajedrez sea utilizable por los ciegos, cambie la vista por una versión audible y un controlador que funcione con el teclado. Supongamos que desea agregar juegos por correo, agregue un controlador que acepte texto. ¿Versión neta del juego? Un controlador que acepte comandos de un socket haría el trabajo. Agregue un bonito render 3d, una nueva y genial vista. El modelo cero requiere cambios El ajedrez sigue siendo ajedrez.

Si combina la entrada con la representación del modelo, pierde esa capacidad. De repente, el ajedrez no es ajedrez, es ajedrez con un mouse que es diferente del ajedrez con un teclado o conexión de red.

metal de piedra
fuente
0

Creo que MVC es tonto, tal vez en áreas específicas funciona bien, pero personalmente incluso los sitios web que escribo no son adecuados para mvc. Hay una razón por la que escuchas frontend, backend y nunca el final de la base de datos o algo más.

En mi opinión, debería haber una API (back-end) y la aplicación que utiliza la API (frontend). Supongo que podría llamar a la solicitud GET al controlador (que simplemente llama a la API de back-end) y al html de la vista, pero por lo general no escucho a la gente hablar de la vista como html puro o modelo como API de backend.

En mi opinión, todo debería ser una API sólida. En realidad, no necesitan ser sólidos (como limpios y bien construidos), pero sus componentes internos deben permanecer privados y la aplicación / frontend / fuera de la API nunca debe decir la conexión de la base de datos ni ser capaz de realizar consultas sin formato.

Ahora, si su código / diseño implica pegamento, está bien. Si en su juego de ajedrez hay algún marcado que puede editar para ocultar la GUI, la GUI recopila los coords / input y llama a MovePiece (srcPosition, dstPostion) (que puede devolver un bool o enum para decir si es un movimiento válido o no ) y estás bien con toda la lógica en el modelo, entonces seguro que lo llamas MVC. Sin embargo, todavía organizaría las cosas por clases y API y me aseguraría de que no haya una clase de fregadero que toque todo (ni ninguna API que tenga que saber sobre todo).


fuente
Sea bienvenido a su opinión, pero esta respuesta no intenta abordar la pregunta del OP.
Caleb
0

Piense en un navegador que muestra una página web estática. El modelo es el HTML. La vista es el resultado real en la pantalla.

Ahora agregue un poco de JavaScript. Ese es el controlador. Cuando el usuario hace clic en un botón o arrastra algo, el Evento se envía al JavaScript, decide qué hacer y altera el HTML (Modelo) subyacente y el navegador / procesador muestra esos cambios en la pantalla (Ver).

Tal vez se haga clic en otro botón, el evento se envíe a algún controlador (Controlador), y puede hacer que se solicite que se envíen más datos a un servicio web. El resultado luego se agrega al HTML (Modelo).

El controlador responde a eventos y controla lo que está en el modelo y, por lo tanto, lo que está en la pantalla / vista.

Retrocediendo un poco, puede pensar en todo el navegador como la Vista y el servidor como el Controlador y los datos como el Modelo. Cuando el usuario hace clic en un botón del navegador el evento que envió al servidor (Controlador), reúne recursos como una página HTML (Modelo) y lo envía de vuelta al navegador para que se muestre (Ver)

En el servidor, ya sea asp, php o java, el 'código' (Controlador) recibe el evento click y consulta una base de datos o repositorio de documentos (Modelo) y crea HTML. Desde el punto de vista del servidor, el resultado de todas sus acciones es una Vista (HTML) de su almacén de datos subyacente (Modelo). Pero desde el punto de vista del cliente, el resultado de su solicitud al servidor es su Modelo (HTML)

Incluso si mezcla su JavaScript en su HTML o su PHP en su HTML, el Modelo, Vista, Controlador aún existe. Incluso si piensa en su solicitud a un servidor y la respuesta del servidor como una simple calle de dos vías, todavía hay un Modelo, una Vista y un Controlador.

Zeus
fuente
-2

En mi experiencia, en un programa tradicional de gui mvc de escritorio, el controlador termina espaciado en la vista. La mayoría de las personas no se toman el tiempo para factorizar una clase de controlador.

el libro de la pandilla de cuatro dice:

Patrones de diseño en Smalltalk MVC

La tríada de clases Modelo / Vista / Controlador (MVC) [KP88] se usa para construir interfaces de usuario en Smalltalk-80. Mirar los patrones de diseño dentro de MVC debería ayudarlo a ver lo que queremos decir con el término "patrón".

MVC consta de tres tipos de objetos. El Modelo es el objeto de la aplicación, la Vista es su presentación en pantalla y el Controlador define la forma en que la interfaz de usuario reacciona a la entrada del usuario. Antes de MVC, los diseños de interfaz de usuario tendían a agrupar estos objetos. MVC los desacopla para aumentar la flexibilidad y la reutilización.

MVC desacopla las vistas y los modelos al establecer un protocolo de suscripción / notificación entre ellos. Una vista debe garantizar que su apariencia refleje el estado del modelo. Cada vez que los datos del modelo cambian, el modelo notifica las vistas que dependen de él. En respuesta, cada vista tiene la oportunidad de actualizarse. Este enfoque le permite adjuntar múltiples vistas a un modelo para proporcionar diferentes presentaciones. También puede crear nuevas vistas para un modelo sin reescribirlo.

El siguiente diagrama muestra un modelo y tres vistas. (Hemos omitido los controladores por simplicidad). El modelo contiene algunos valores de datos, y las vistas que definen una hoja de cálculo, un histograma y un gráfico circular muestran estos datos de varias maneras. El modelo se comunica con sus vistas cuando cambian sus valores, y las vistas se comunican con el modelo para acceder a estos valores.

Tomado al pie de la letra, este ejemplo refleja un diseño que desacopla las vistas de los modelos. Pero el diseño es aplicable a un problema más general: desacoplar objetos para que los cambios en uno puedan afectar a cualquier número de otros sin requerir que el objeto modificado conozca los detalles de los demás. Este diseño más general es descrito por el patrón de diseño del Observador (página 293).

Otra característica de MVC es que las vistas se pueden anidar. Por ejemplo, un panel de control de botones podría implementarse como una vista compleja que contiene vistas de botones anidados. La interfaz de usuario para un inspector de objetos puede consistir en vistas anidadas que pueden reutilizarse en un depurador. MVC admite vistas anidadas con la clase CompositeView, una subclase de Vista. Los objetos CompositeView actúan igual que los objetos View; una vista compuesta se puede usar donde sea que se pueda usar una vista, pero también contiene y administra vistas anidadas.

Nuevamente, podríamos pensar en esto como un diseño que nos permite tratar una vista compuesta al igual que tratamos uno de sus componentes. Pero el diseño es aplicable a un problema más general, que ocurre cada vez que queremos agrupar objetos y tratar el grupo como un objeto individual. Este diseño más general es descrito por el patrón de diseño Compuesto (163). Le permite crear una jerarquía de clases en la que algunas subclases definen objetos primitivos (por ejemplo, Button) y otras clases definen objetos compuestos (CompositeView) que ensamblan las primitivas en objetos más complejos.

MVC también le permite cambiar la forma en que una vista responde a la entrada del usuario sin cambiar su presentación visual. Es posible que desee cambiar la forma en que responde al teclado, por ejemplo, o hacer que use un menú emergente en lugar de teclas de comando. MVC encapsula el mecanismo de respuesta en un objeto Controlador. Existe una jerarquía de clase de controladores, lo que facilita la creación de un nuevo controlador como una variación de uno existente.

Una vista utiliza una instancia de una subclase de Controlador para implementar una estrategia de respuesta particular; Para implementar una estrategia diferente, simplemente reemplace la instancia con un tipo diferente de controlador. Incluso es posible cambiar el controlador de una vista en tiempo de ejecución para permitir que la vista cambie la forma en que responde a la entrada del usuario. Por ejemplo, una vista se puede deshabilitar para que no acepte entradas simplemente dándole un controlador que ignore los eventos de entrada.

La relación Vista-Controlador es un ejemplo del patrón de diseño de la Estrategia (315). Una estrategia es un objeto que representa un algoritmo. Es útil cuando desea reemplazar el algoritmo, ya sea estática o dinámicamente, cuando tiene muchas variantes del algoritmo o cuando el algoritmo tiene estructuras de datos complejas que desea encapsular.

MVC utiliza otros patrones de diseño, como el Método de fábrica (107) para especificar la clase de controlador predeterminada para una vista y el Decorador (175) para agregar desplazamiento a una vista. Pero las relaciones principales en MVC están dadas por los patrones de diseño de Observador, Compuesto y Estrategia.

Ray Tayek
fuente
1
Parece que esta publicación completa menos los dos primeros párrafos se toma textualmente de Patrones de diseño . He formateado esa sección como una cita para que los lectores entiendan eso: edite si he citado párrafos que son suyos.
Caleb
1
Tengo que estar en desacuerdo con su opinión de que "el controlador termina dividido en la vista". Quizás varía con la plataforma y el marco que está utilizando, pero es mucho más común en la programación de Cocoa y Cocoa Touch crear controladores apropiados que omitirlos. Si un programador de Objective-C omite una de las categorías, es casi seguro que sea el modelo que sufra.
Caleb
Si acepta que esta es la interpretación "adecuada" de MVC, MVC no compra absolutamente nada. También puede ser MV y omitir la C porque cada vez que crea una nueva Vista también necesita crear un nuevo Controlador. Entonces, ¿qué sentido tiene esforzarse por separarlos más que por razones teóricas de separación de preocupaciones?
Dunk