model-view-controller - examples - qt documentation
¿Por qué Qt está haciendo un uso indebido de la terminología de modelo/vista? (5)
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:
Sin embargo, creo que ellos mal denominaron los roles de los objetos y creo que
- Lo que ellos llaman Vista con Controlador combinado es, de hecho, solo una Vista.
- Lo que ellos llaman Modelo es de hecho solo Controlador.
- Si realmente quieres tener un modelo, sería en algún lugar donde están sus "Datos".
Me refiero a la manera habitual y sensata en la que usarías el componente Qt model / view en tu aplicación. Aquí están las razones:
- Este es típicamente el componente Qt que se usa tal cual, sin agregar ninguna lógica del Controlador específica para sus objetos)
- Esto no es un Modelo, simplemente porque debe implementar varios métodos Qt como rowCount, columnCount, data etc. que no tienen nada que ver con su modelo. De hecho, hay métodos modelo típicos que se encuentran en Controladores. Por supuesto, puede implementar tanto la lógica de controlador como la de modelo, 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, tal como indican.
- Como se dijo en el motivo 2. si desea separar la lógica del modelo, seguramente no es el cuadro azul de la imagen, sino el cuadro discontinuo "Datos" (que se comunica con datos reales, por supuesto).
¿Qt está equivocado en su terminología, o simplemente soy yo quien no comprende? (Por cierto: la razón por la cual no es una cuestión académica es que he comenzado 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)
Respuesta corta
El MVC de Qt solo se aplica a una estructura de datos . Cuando se habla de una aplicación MVC , no se debe pensar en QAbstractItemModel
o QListView
.
Si desea una arquitectura MVC para su programa completo, Qt no tiene un marco de modelo / vista tan "enorme". Pero para cada lista / árbol de datos en su programa puede usar el enfoque de Qt MVC, que de hecho tiene un controlador dentro de su vista. Los datos están dentro o fuera del modelo; esto depende del tipo de modelo que esté usando (subclase del modelo propio: probablemente dentro del modelo; por ejemplo, QSqlTableModel: fuera (pero quizás dentro de la caché) del modelo). Para unir sus modelos y puntos de vista, use clases propias que luego implementen la lógica comercial .
Respuesta larga
El enfoque y la terminología de modelo / vista de Qt:
Qt proporciona vistas simples para sus modelos. Tienen un controlador incorporado: 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 quiere almacenarlos. Pero extiende un QAbstractItemModel a sus necesidades agregando sus contenedores de datos a la subclase y haciendo que la interfaz del modelo acceda a sus datos. Entonces, de hecho, y supongo que no te gusta esto, el problema es que necesitas programar el modelo, así que cómo se accede y se modifica la información en tu estructura de datos.
En la terminología de MVC, el modelo contiene tanto los datos como la lógica . En Qt, depende de usted si incluye o no parte de la lógica de su negocio dentro de su modelo o si lo deja afuera, siendo una "vista" por sí mismo. Ni siquiera está claro qué se entiende por lógica: ¿Seleccionar, renombrar 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? => Póngalo dentro de la subclase modelo.
Mi opinión personal:
Es muy difícil proporcionar un sistema bueno y genérico de MV (C) 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 quiera 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), puede asignar los 3 campos a 3 columnas diferentes o a 3 roles diferentes. No me gustan ambos enfoques.
Creo que el marco de modelos / vistas de Qt solo es útil cuando quieres mostrar estructuras de datos simples . Se vuelve difícil de manejar si los datos son de tipos personalizados o estructurados, no 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 atributos diferentes (una instancia de una clase), el marco de modelo / vista de Qt no es la manera correcta de separar la lógica de la interfaz de usuario.
Para resumir, creo que el marco de modelo / vista de Qt es útil solo si uno de los widgets de visor de Qt está viendo tus datos. Es totalmente inútil si está por escribir su propio visor para un modelo que solo contiene una entrada, por ejemplo, la configuración de su aplicación, o si sus datos no son de tipos imprimibles.
¿Cómo utilicé el modelo / vista de Qt dentro de una aplicación (más grande)?
Una vez escribí (en un equipo) una aplicación que usa múltiples modelos Qt para administrar datos. Decidimos crear una DataRole
para contener los datos reales que eran de un tipo personalizado diferente para cada subclase de modelo diferente. Creamos una clase de modelo externo llamada Model
contiene todos los diferentes modelos de Qt. También creamos una clase de vista exterior llamada View
contiene las ventanas (widgets) que están conectadas a los modelos dentro de Model
. Entonces este enfoque es un Qt MVC extendido, adaptado a nuestras propias necesidades. Las clases Model
y View
no tienen nada que ver con el Qt MVC.
¿Dónde pusimos la lógica ? Creamos clases que realizaban los cálculos reales sobre los datos leyendo los datos de los modelos fuente (cuando cambiaron) y escribiendo los resultados en modelos objetivo. Desde el punto de vista de Qt, estas clases de lógica serían vistas, ya que se "conectan" a modelos (no "vista" para el usuario, sino una "vista" para la parte de 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. Como las vistas de Qt ya interpretan la entrada del usuario, como renombrar y mover elementos, esto no fue necesario. Pero lo que necesitábamos era una interpretación de la interacción del usuario que vaya más allá de las vistas de Qt.
Como la función del modelo es responder a solicitudes de información, creo que no hay nada de malo en definir tales métodos como rowCount
, rowCount
, etc. Creo que Model es una especie de contenedor para el origen de datos (no importa de qué se rowCount
SQL table o simplemente un array), proporciona datos en forma estándar, y usted debe definir los métodos que dependen de la estructura de su fuente de datos.
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 un modelo de nivel superior.
Siento que la confusión surge de su clase QAbstractModelItem. Esta clase no es un elemento modelo, sino que es 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. entonces su interfaz tiene que soportar todas estas variaciones del modelo. Es cierto que esto hace que los elementos del modelo sean bastante complejos, y el código de pegamento para que funcione con un modelo real parece estirar un poco la metáfora.
Estoy de acuerdo con usted en que el nombramiento de Qt es engañoso. En mi opinión, sin embargo, el problema no está solo en Qt, sino en todos los marcos que nos permiten adherirnos al principio de separación de preocupaciones cuando implementamos nuestras UI. Cuando a alguien se le ocurre un marco así, y encuentra una buena manera de mantener las "cosas" separadas, siempre se sienten obligados a tener módulos que llaman "Modelo" y otros que llaman "Ver". A lo largo de los años, he trabajado con estos marcos:
- MFC
- Qt
- Oscilación
- 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 "Vista", "Modelo" y "Controlador" (si es que lo hay), lo hará descubre que hay diferencias muy grandes. Sin duda sería útil tener una comparación de los diferentes conceptos y terminologías, para que las personas que cambian de un marco a otro tengan la oportunidad de mantenerse cuerdas, pero eso requeriría mucho trabajo e investigación. Una buena lectura es la overview Martin Fowler.
Ya que hay tantas ideas diferentes sobre cómo se ve un patrón MVC, ¿cuál es el correcto? En mi opinión, se debe recurrir a las personas que inventaron MVC cuando queremos saber cómo se debe implementar "correctamente". En el papel original de smalltalk dice:
La vista administra la salida gráfica y / o textual a la parte de la visualización de mapa de bits que está asignada a su aplicación. El controlador interpreta las entradas de mouse y teclado del usuario, ordenando al modelo y / o a la vista que cambien según corresponda. Finalmente, el modelo maneja 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 desde el controlador).
A la luz de eso, respondería a sus tres principales preocupaciones de este modo:
- De hecho, un componente de Qt "gestiona la salida [...] gráfica" e "interpreta las entradas de mouse y teclado", por lo que podría llamarse Vista y controlador combinados con respecto a la definición anterior.
- Estoy de acuerdo en que usted / debería verse obligado a fusionar el Controlador y el Modelo (nuevamente con respecto a la definición anterior).
- 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, lidiar 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, lo mejor es averiguar qué significa realmente Qt cuando se usan los términos "Modelo" y "Vista" y usar los términos en su forma mientras estamos programando con Qt. Si le siguen molestando, esto solo lo hará más lento, y la forma en que se configuran las cosas en Qt permite un diseño elegante, que pesa más que sus convenciones de nombres "incorrectos".
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 amigable con MVC. La respuesta es que los primeros desarrolladores de Qt creen que desacoplando V de C en aplicaciones GUI hace que los V y C sean malos. El diseño de QWidget intenta hacer que sea sencillo vincular estrechamente la interoperació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.