¿Por qué Qt hace un mal uso de la terminología de modelo / vista?

104

Creo que la terminología utilizada en Qt con controles de modelo / vista es defectuosa. En su página de explicación , afirman que simplificaron el MVC a MV fusionando View y Controller y están dando la siguiente imagen:

imagen que explica Qt MVC

Sin embargo, creo que nombraron mal los roles de los objetos y creo que,

  1. Lo que llaman Vista con controlador fusionado es, de hecho, solo Vista.
  2. Lo que ellos llaman Modelo es, de hecho, solo controlador.
  3. Si realmente quieres tener un modelo, debería estar en algún lugar donde estén sus "Datos".

Estoy hablando de la forma habitual y sensata en que usaría el componente de vista / modelo Qt en su aplicación. Estas son las razones:

  1. Este es típicamente un componente Qt que se usa tal cual, sin agregar ninguna lógica de controlador específica a sus objetos)
  2. Esto no es un modelo, solo porque debe implementar varios métodos Qt como rowCount, columnCount, datos, etc.que no tienen nada que ver con su modelo. De hecho, hay métodos de modelo típicos que se encuentran en Controllers. Por supuesto, puede implementar tanto la lógica del controlador como la del modelo aquí, pero primero sería un diseño de código bastante malo y, en segundo lugar, combinaría el controlador y el modelo, no el controlador y la vista como se indica.
  3. Como se dijo en la razón 2, si desea separar la lógica del modelo, seguramente no es el cuadro azul de la imagen, sino el cuadro de "Datos" discontinuo (comunicándose con los datos reales, por supuesto).

¿Qt está mal en su terminología, o soy yo quien no entiende? (Por cierto: la razón por la que no es una cuestión académica es que comencé a codificar mi proyecto siguiendo su nombre y pronto descubrí que el código claramente no es correcto. Fue solo después de eso cuando me di cuenta de que debería no intente poner la lógica del modelo en lo que ellos llaman Modelo)

gorn
fuente
1
MFC estableció el estándar para guis de vista / modelo de 2 partes con CDoc y CView: no hay ninguna razón por la que un MVC en particular sea 'correcto'
Martin Beckett
@Martin B: Voy a echar un vistazo a MFC, sin embargo, incluso si hay diferentes modelos de MVC, creo que deberían ser consistentes en su terminología y creo que he presentado argumentos válidos, por qué la terminología utilizada no es consistente en este caso particular. Simplemente afirman que han combinado Vista y Controlador, pero creo que es simplemente engañoso en el caso. No creo que haya un modelo MVC donde toda la lógica específica de la aplicación, ya sea la presentación o la lógica del modelo, deba colocarse en un objeto llamado Modelo.
gorn
1
@Martin B: También bajo la terminiología qt, todos los modelos tienen una api común que no tiene nada que ver con la estructura del modelo, sino que tiene que ver con la estructura general del controlador, lo que claramente indica que no es correcto llamarlo modelo. No digo que haya UN modelo MVC correcto, pero no significa que cualquier cosa pueda llamarse modelo MVC. Tal vez también tenga fallas en MFC y puedo echarle un vistazo, pero estoy más interesado en que Qt lo haga bien, ese MFC que no tengo la intención de usar. ¿Tiene algún buen enlace donde se explique la separación de vista / modelo MFC?
gorn
1
La terminología de MVC no se acuerda unánimemente, por lo que su pregunta podría considerarse argumentativa. Sin embargo, muchos estarán de acuerdo con el excelente trabajo realizado por Martin Fowler ( martinfowler.com/eaaDev/index.html ). Por lo general, el controlador maneja la entrada del usuario y, en este sentido, los widgets Qt definitivamente combinan vista y controlador.
Arnold Spence
1
Entiendo que MVC tiene muchos sabores pero no significa que cualquier cosa pueda ser MVC. Qt ha cruzado la línea y he dado varias razones. Martin Fowler explica diferentes tipos de MVC, pero ninguno de ellos es lo suficientemente similar a lo que Qt pronuncia MVC. El más similar es martinfowler.com/eaaDev/PresentationModel.html , pero esto distingue entre la parte Modelo de presentación = Controlador (interacción del usuario) y Modelo (lógica de datos). Entonces, aunque no existe una definición precisa de MVC, Qt no sigue ninguno de ellos. Si puede darme un enlace a dicha definición, hágalo.
gorn

Respuestas:

78

Estoy de acuerdo con usted en que el nombre de Qt es engañoso. En mi opinión, sin embargo, el problema no es solo de Qt, sino que es compartido por todos los marcos que nos permiten adherirnos al principio de separación de preocupaciones al implementar nuestras UI. Cuando a alguien se le ocurre un marco de este tipo y encuentra una buena manera de mantener "las cosas" separadas, siempre se siente obligado a tener módulos que llaman "Modelo" y otros que llaman "Vista". A lo largo de los años he trabajado con estos marcos:

  • MFC
  • Qt
  • Columpio
  • SWT
  • WPF con MVVM

Si compara cómo se usan los términos "Modelo" y "Vista" en estos marcos, y qué responsabilidades tienen las clases en la "Vista", el "Modelo" y el "Controlador" (si hay uno), obtendrá descubre que hay diferencias muy grandes. Ciertamente sería útil tener una comparación de los diferentes conceptos y terminologías, de modo que las personas que cambian de un marco a otro tengan la oportunidad de mantenerse cuerdos, pero eso requeriría mucho trabajo e investigación. Una buena lectura es la descripción general de Martin Fowler .

Dado que hay tantas ideas diferentes sobre cómo puede verse un patrón MVC, ¿cuál es la correcta? En mi opinión, deberíamos acudir a las personas que inventaron MVC cuando queramos saber cómo se supone que debe implementarse "correctamente". En el papel original de Smalltalk dice:

La vista gestiona la salida gráfica y / o textual de la parte de la pantalla de mapa de bits que se asigna a su aplicación. El controlador interpreta las entradas del mouse y del teclado del usuario, ordenando al modelo y / o la vista que cambie según corresponda. Finalmente, el modelo administra el comportamiento y los datos del dominio de la aplicación, responde a las solicitudes de información sobre su estado (generalmente desde la vista) y responde a las instrucciones para cambiar el estado (generalmente del controlador).

A la luz de eso, respondería a sus tres preocupaciones principales de la siguiente manera:

  1. De hecho, un componente Qt "gestiona la salida [...] gráfica" e "interpreta las entradas del mouse y del teclado", por lo que podría denominarse Vista y Controlador fusionados con respecto a la definición anterior.
  2. Estoy de acuerdo en que está / estaría obligado a fusionar Controlador y Modelo (nuevamente con respecto a la definición anterior).
  3. Estoy de acuerdo, de nuevo. El modelo solo debe administrar los datos del dominio de la aplicación . Esto es lo que ellos llaman "datos". Claramente, tratar con filas y columnas, por ejemplo, normalmente no tiene nada que ver con nuestro dominio de aplicaciones.

¿Dónde nos deja? En mi opinión, es mejor averiguar qué significa realmente Qt cuando se usan los términos "Modelo" y "Vista" y usar los términos a su manera mientras programamos con Qt. Si sigues molestándote, solo te ralentizará, y la forma en que están configuradas las cosas en Qt permite un diseño elegante, que pesa más que sus convenciones de nomenclatura "incorrectas".

Tilo
fuente
2
Yo diría que el delegado es el controlador del Qt, ya que los delegados reciben y envían la entrada al modelo, que actualiza la vista a través de señales.
Peregring-lk
82

Respuesta corta

MVC de Qt solo se aplica a una estructura de datos . Cuando se habla de una aplicación MVC , no debe pensar en QAbstractItemModelo QListView.

Si desea una arquitectura MVC para todo su programa, Qt no tiene un marco de modelo / vista tan "enorme". Pero para cada lista / árbol de datos en su programa, puede usar el enfoque Qt MVC que de hecho tiene un controlador a su vista. Los datos están dentro o fuera del modelo; esto depende del tipo de modelo que esté utilizando (propia subclase de modelo: probablemente dentro del modelo; por ejemplo, QSqlTableModel: fuera (pero quizás almacenado en caché) del modelo). Para unir sus modelos y vistas, use clases propias que luego implementen la lógica empresarial .


Respuesta larga

Enfoque y terminología de modelo / vista de Qt:

Qt proporciona vistas simples para sus modelos. Tienen un controlador integrado: seleccionar, editar y mover elementos es algo que en la mayoría de los casos un controlador "controla". Es decir, interpretar la entrada del usuario (clics y movimientos del mouse) y dar los comandos apropiados al modelo.

Los modelos de Qt son de hecho modelos que tienen datos subyacentes. Los modelos abstractos, por supuesto, no contienen datos, ya que Qt no sabe cómo desea almacenarlos. Pero se extiende una QAbstractItemModel a sus necesidades mediante la adición de sus contenedores de datos a la subclase y haciendo que la interfaz de modelo de acceso a sus datos. Así que, de hecho, y supongo que no lo hace así, el problema es que se necesita programar el modelo, así que ¿cómo se accede y modificados en su estructura de datos de datos.

En la terminología MVC, el modelo contiene tanto los datos como la lógica . En Qt, depende de usted si incluye o no parte de su lógica empresarial dentro de su modelo o la pone fuera, siendo una "vista" por sí misma. Ni siquiera está claro qué se entiende por lógica: ¿seleccionar, cambiar el nombre y mover elementos? => ya implementado. ¿Haciendo cálculos con ellos? => Ponlo fuera o dentro de la subclase del modelo. ¿Almacenar o cargar datos desde / hacia un archivo? => Ponlo dentro de la subclase del modelo.


Mi opinión personal:

Es muy difícil proporcionar un sistema MV (C) bueno y genérico a un programador. Debido a que en la mayoría de los casos los modelos son simples (por ejemplo, solo listas de cadenas), Qt también proporciona un QStringListModel listo para usar. Pero si sus datos son más complejos que las cadenas, depende de usted cómo desea representar los datos a través de la interfaz modelo / vista de Qt. Si tiene, por ejemplo, una estructura con 3 campos (digamos personas con nombre, edad y sexo), podría asignar los 3 campos a 3 columnas diferentes o a 3 roles diferentes. No me gustan ambos enfoques.

Creo que el marco de modelo / vista de Qt solo es útil cuando desea mostrar estructuras de datos simples . Se vuelve difícil de manejar si los datos son de tipos personalizados o no están estructurados en un árbol o lista (por ejemplo, un gráfico). En la mayoría de los casos, las listas son suficientes e incluso en algunos casos, un modelo solo debe contener una sola entrada. Especialmente si desea modelar una sola entrada con diferentes atributos (una instancia de una clase), el marco de modelo / vista de Qt no es la forma correcta de separar la lógica de la interfaz de usuario.

Para resumir, creo que el marco de modelo / vista de Qt es útil si y solo si uno de los widgets de visor de Qt está viendo sus datos . Es totalmente inútil si está a punto de escribir su propio visor para un modelo que contiene solo una entrada, por ejemplo, la configuración de su aplicación, o si sus datos no son de tipo imprimible.


¿Cómo usé el modelo / vista Qt dentro de una aplicación (más grande)?

Una vez escribí (en equipo) una aplicación que usa múltiples modelos Qt para administrar datos. Decidimos crear un DataRolepara contener los datos reales que eran de un tipo personalizado diferente para cada subclase de modelo diferente. Creamos una clase de modelo externa llamada que Modelcontiene todos los diferentes modelos de Qt. También creamos una clase de vista externa llamada Viewmantener las ventanas (widgets) que están conectadas a los modelos internos Model. Entonces, este enfoque es un Qt MVC extendido, adaptado a nuestras propias necesidades. Tanto Modely Viewclases mismas no tienen nada que ver con el Qt MVC.

¿Dónde pusimos la lógica ? Creamos clases que realizaban los cálculos reales de los datos leyendo datos de los modelos de origen (cuando cambiaban) y escribiendo los resultados en los modelos de destino. Desde el punto de vista de Qt, estas clases lógicas serían vistas, ya que se "conectan" a modelos (no "vista" para el usuario, sino una "vista" para la parte lógica de negocios de la aplicación).

¿Dónde están los controladores ? En la terminología MVC original, los controladores interpretan la entrada del usuario (mouse y teclado) y dan comandos al modelo para realizar la acción solicitada. Dado que las vistas de Qt ya interpretan la entrada del usuario como cambiar el nombre y mover elementos, esto no era necesario. Pero lo que necesitábamos era una interpretación de la interacción del usuario que fuera más allá de las vistas de Qt.

leemes
fuente
Lo más irritante es que tienes que implementar clases de modelo Qt totalmente diferentes según la vista que desees. Un modelo para una vista de lista no admitirá correctamente una vista de árbol y viceversa. Un modelo MVC canónico puede admitir una gran cantidad de tipos de vistas diferentes.
smerlin
3
@smerlin: No creo que eso sea correcto. Tanto QListView como QTreeView solo requieren una interfaz QAbstractItemView, lo que significa que una subclase personalizada de esa, o una clase concreta como QStandardItemModel debe cumplir ese requisito para ambos. Puede conducir un árbol y listar un modelo.
jdi
1
@jdi: hay casos en los que sus datos son a la vez, una lista y un árbol ... por ejemplo, le gustaría mostrar su sistema de archivos como un árbol, o todos los archivos como una lista. Los modelos Qts no permiten eso correctamente. Una implementación de QAbstractItemModel que admite vistas de árbol, permite solo mostrar todos los archivos / directorios en su directorio raíz como una lista, pero no puede mostrar todos los archivos como una lista. Y no diga que mostrar los datos del árbol como una lista no puede ser útil. Por ejemplo, puede, por ejemplo, ordenarlos fácilmente para encontrar el archivo con el mayor tamaño si muestra sus archivos como una lista, las vistas de árbol no lo permitirían.
smerlin
1
Dicho esto, el modelo de proxy es más algo de su vista (ya que modifica cómo se ven los datos ) y, por lo tanto, debería pertenecer a su vista. Si lees mi respuesta larga: En la Viewclase "grande" , debes agregar el modelo proxy, que tiene el modelo de árbol como modelo subyacente y es utilizado por la vista de lista de tu sistema de archivos. Como está diciendo: no debería haber dos modelos para los mismos datos. ¡Nunca! (Pero los modelos proxy no cuentan como modelos separados)
Leemes
1
@SamPinkus Eso es porque no hay un o un no claro a esta pregunta. Además, hay diferentes implementaciones de QAbstractItemModel, algunas de las cuales son modelos en el sentido de MVC y otras no.
leemes
12

La terminología no es correcta o incorrecta, es útil o inútil.

Puede cambiar un poco la pregunta y preguntar por qué Qt no es más compatible con MVC. La respuesta a es que los primeros desarrolladores de Qt creen que el desacoplamiento de V de C en las aplicaciones GUI genera Vs y Cs malas. El diseño de QWidget intenta simplificar la vinculación de la interacción de entrada del mouse con las decisiones de salida de píxeles, y puede ver cómo ese no es el camino hacia MVC.

arnt
fuente
Veo su punto y, básicamente, preguntaría por qué Qt no es más compatible con MVC, pero es muy difícil de hacer cuando la terminología MVC utilizada en la documentación de Qt es DIFERENTE de lo que MVC se usa normalmente (como expliqué en la pregunta). Y cuando hay una terminología ampliamente utilizada y alguien la usa de manera muy diferente al resto del mundo, tiendo a pensar que no solo es inútil, sino que es simplemente INCORRECTA y confusa (esa confusión me llevó a hacer la pregunta en el primer sitio). Me interesaría mucho si tuviera algún enlace a estas cosas que se están discutiendo o explicando en alguna parte. Gracias
gorn
No puedo decir nada sobre por qué los documentos de Qt ahora hablan de MVC de la forma en que lo hacen. Dejé Trolltech hace mucho tiempo y estoy desconcertado por algunas de las cosas que se han hecho con la documentación desde que me fui. (Sin embargo, en mi blog a veces despotricar un poco sobre eso)
arnt
¿Tiene alguna idea de cómo se ha acordado la terminología MVC en Qt. ¿Se usó durante la escritura del código o solo más tarde durante el proceso de documentación?
gorn
No usamos la palabra "MVC" en la documentación de Qt durante mi tiempo en Trolltech. En general, creo que es mejor documentar lo que hay, no escribir sobre lo que no está. Sin embargo, en gitorious puedes averiguar quién agregó ese texto y agregar a esa persona directamente.
Arnt
1
Un comentario diferente. Hablamos de MVC durante el diseño y la frase de implementación temprana de Qt (cuando Trollech era una empresa de tres personas), y evaluamos un conjunto de herramientas GUI que usaba MVC "correctamente", no recuerdo su nombre. Nuestra opinión fue que ese conjunto de herramientas era terrible de usar, y que MVC fue gran parte de la razón de eso.
Arnt
3

Como la función del modelo es responder a las solicitudes de información, creo que no hay nada de malo en definir métodos como rowCount, columnCountetc. Creo que el modelo es una especie de contenedor para la fuente de datos (no importa qué es una tabla SQL o simplemente una matriz) , proporciona datos en forma estándar, y debería definir métodos dependiendo de la estructura de su fuente de datos.

Dmitry
fuente
2

Creo que su terminología es correcta ... aunque en aplicaciones reales encuentro que puede ser muy fácil difuminar las líneas entre modelo, vista y controlador dependiendo de su nivel de abstracción: la vista de un nivel puede ser el modelo de un nivel superior.

Siento que la confusión surge de su clase QAbstractModelItem. Esta clase no es un elemento de modelo, sino más bien una interfaz para un modelo. Para hacer que sus clases de vista interactúen con el modelo, tuvieron que crear una interfaz abstracta genérica para el modelo. Sin embargo, un modelo puede ser un solo elemento, una lista de elementos, una tabla de 2 o más dimensiones de elementos, etc; por lo que su interfaz debe admitir todas estas variaciones de modelos. Es cierto que esto hace que los elementos del modelo sean bastante complejos, y el código adhesivo para que funcione con un modelo real parece estirar un poco la metáfora.

Chris Morlier
fuente
Aunque estoy de acuerdo con usted con la clase QAbstractModelItem, también creo que incluso sin esta complicación, su MVC tiene un nombre incorrecto. ¿Podría explicar por qué cree que su terminología es correcta? Me encantaría saber por qué no estoy en lo cierto en ninguno de mis tres argumentos.
gorn
0

Creo que ... Lo que ellos llaman Modelo es, de hecho, solo Controlador.

No, su "modelo" definitivamente no es un controlador.

El controlador es la parte de los controles visibles para el usuario que modifican el modelo (y por tanto modifican indirectamente la vista). Por ejemplo, un botón "eliminar" es parte del controlador.

Creo que a menudo hay confusión porque muchos ven algo como "el controlador modifica el modelo" y piensan que esto significa las funciones mutantes en su modelo, como un método "deleteRow ()". Pero en MVC clásico, el controlador es específicamente la parte de la interfaz de usuario. Los métodos que mutan el modelo son simplemente parte del modelo.

Desde que se inventó MVC, su distinción entre controlador y vista se ha vuelto cada vez más tensa. Piense en un cuadro de texto: le muestra algo de texto y le permite editarlo, entonces, ¿es vista o controlador? La respuesta tiene que ser que es parte de ambos. Cuando trabajaba en un teletipo en la década de 1960, la distinción era más clara, piense en el ed, ¡pero eso no significa que las cosas fueran mejores para el usuario en ese entonces!

Es cierto que su QAbstractItemModel es de un nivel bastante superior al que normalmente tendría un modelo. Por ejemplo, los elementos en él pueden tener un color de fondo (técnicamente un pincel), ¡que es un atributo decididamente visual! Entonces, hay un argumento de que QAbstractItemModel es más como una vista y sus datos son el modelo. La verdad es que está en algún lugar entre los significados clásicos de vista y modelo. Pero no veo cómo es un controlador; en todo caso, ese es el widget QT que lo usa.

Arthur Tacca
fuente