Concepto y preguntas básicas sobre separación de lógica(C++) y GUI(Qt)
user-interface separation-of-concerns (2)
Terminé un proyecto en C++
. Es una aplicación de consola, creada con CodeBlocks. Aunque considero que no es tan importante en el alcance de esta pregunta: la aplicación gestiona datos sobre facturas y clientes de una empresa pequeña. El programa está completo y podría expandirse muy fácilmente mediante una interfaz de usuario de consola (en este momento, lo ejecuto como programador).
¡Ahora decidí aprender programación de GUI usando Qt
y QtCreator con su QtDesigner!
No solo porque es una práctica común separar la lógica de la GUI cuando se crea una aplicación GUI, quiero poner mi proyecto en práctica en dos partes principales, por supuesto, la lógica y la GUI . Usted ya sabe que la parte lógica está completa; lo que tengo es una carpeta de proyecto llamada project
contiene otra carpeta (proyecto CodeBlocks) project_logic
que contiene varias clases, por lo tanto archivos de cabecera y de implementación (y una principal, que por supuesto será obsoleta, eventualmente). También contiene archivos de / en los que el programa lee / escribe. Está escrito en C++
"puro" y no utiliza ninguno de los medios proporcionados por Qt
y es importante para mí que siga siendo así .
Ahora agregué un proyecto Qt
project_gui
en la project_gui
del project
y comencé a crear la GUI, implementando solo la funcionalidad más básica, como cambiar entre diálogos, cerrar la aplicación, etc. Hasta ahora no sabe nada sobre su back-end futuro ( project_logic
)
Como tercer componente, necesito algún tipo de control que vincule la lógica de la aplicación con su GUI. Aquí viene mi pregunta conceptual: ¿Cuál es la mejor manera de juntarlos en una sola aplicación?
Sugerencias
Dado que
project_logic
podría funcionar solo como una aplicación de consola, ya proporciona los componentes y funciones de control más esenciales. Esto seguirá así, porque quiero mantener su funcionalidad independiente. Aún más porque soy totalmente nuevo en la programación de GUI y / o en dos semanas podría pasar a crear otra GUI para la misma lógica. El resultado sería que las clases de la parte lógica se incluyen en la fuente de la GUI como cualquier otro encabezado y se usan para crear un programa con funcionalidad completa. Validar la entrada del usuario descansa en la parte de la GUI. La lógica del programa en cualquier caso se mantendría actualizable.Para hacer que la GUI sea lo más reutilizable posible; ¿Debería implementar un tercer componente à la
project_controlling
que proporcione interacción entre la GUI y la lógica (validación de la entrada del usuario realizada mediante el control) en el sentido de que cada uno de los dos sigue siendo lo más independiente posible? La GUI no incluye los encabezados de la lógica, por así decirlo, sino que incluye el control de los encabezados?
El segundo punto puede sonar un poco extraño, lo admito; para decirlo brevemente, mis objetivos son:
- Mantener el estándar
project_logic
C++
e independiente (en términos de parcheo, agregar funcionalidad, etc.) y - usando
Qt
para GUI a la separación máxima (al mismo tiempo razonable) de la GUI y la lógica.
Trenes de pensamientos
¿Debo incluir los encabezados
project_logic
través de#include "../project_logic/header1.h"
etc.? (Puede haber un problema con el uso de las clases, que publicaré en otra pregunta).¿Debería incluirlos como un subproyecto?
¿Cómo conectaría las partes "en código"?
¿Las funciones lógicas aún encuentran los archivos que mencioné antes (lectura / escritura)?
Tenga en cuenta lo siguiente: ¡Soy nuevo en la programación de GUI! Y di lo mejor de mí para explicar mis pensamientos / problemas ... Sin embargo, conozco C y C ++ y escribo aplicaciones de consola que utilizo para, por ejemplo, simulaciones en la universidad y puedo manejar las cosas estándar bastante bien, creo. Incluso si el potencial respondedor desea sugerir un enfoque muy diferente, agradecería una "solución" para el concepto que propuse. El motivo de eso lo expliqué en la introducción. Sin embargo, es necesario mencionar que estoy interesado en escuchar diferentes sugerencias.
Decidí publicar la pregunta después de hacer algunas investigaciones e intenté hacerlo lo mejor posible en "prueba y error" antes. Hay mucha información sobre este tema en StackOverflow y en otros foros, así que quería presentar mi idea y recopilar críticas e insumos, en lugar de agregar otro "¿cómo?" al batiburrillo de preguntas.
Dado que esta pregunta es sobre el enfoque general, quizás (bastante seguro ... :-P) formule más preguntas técnicas más adelante, que me gustaría editar en esta pregunta (hipervínculos) tan pronto como aparezcan. Sin embargo, las recetas básicas en este asunto, si están disponibles, son bienvenidas, por supuesto.
Después de algunos comentarios y respuestas, me gustaría publicar un pequeño EDIT solo para aclarar las cosas:
Estado actual de la lógica
-
project_logic
está más o menos terminado y codificado en CodeBlocks como un proyecto CodeBlocks. - Podría funcionar como una aplicación de consola con "interfaz de usuario de consola". (Tiene un
main.cpp
que ahora solo se usa para la depuración). - Sus componentes se dividen en clases (encabezados y archivos de implementación de cpp) tanto como sea posible.
Estado actual de GUI
-
project_gui
se está configurando como un proyecto Qt-Widget-Application (usando QtCreator / Designer). - Hasta ahora, solo es GUI y nada más (no hay conexión con
project_logic
de ninguna manera).
Objetivos y ...
... el flujo de trabajo , quiero seguir, ya que este es mi primer gran proyecto:
-
project_logic
yproject_gui
no saldrán de sus directorios respectivos; ambos están en un directorio llamadoproject
. (Excepción: la lógica se exportará como dll (o algo similar) si es necesario , que luego se proporciona a la GUI). - Si había cosas que cambiar en el
project_logic
, quiero hacerlo en CodeBlocks (y repetir una posible exportación como se describe arriba). -
project_logic
(o cualquier tercera capa como por ejemploproject_controlling
) tiene que hacerse desechable paraproject_gui
de la manera más fácil imaginable ... (ver Trens of thoughts number 1) :-P
- Si tiene proyectos separados :
Cuando haya desarrollado diferentes partes de su aplicación en diferentes proyectos, la manera más fácil es simplemente vincular su proyecto principal con las bibliotecas y usarlas. Por lo tanto, en su caso, debe proporcionar el dll para la lógica del proyecto que se desarrolla y compila en CodeBlocks para su proyecto Qt, vincularlo y usar las clases.
Por ejemplo, puede colocar los archivos de encabezado de su biblioteca en una carpeta llamada Logic
y las versiones de depuración y liberación de los archivos .lib
en carpetas relevantes y vincular su aplicación:
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/Logic/release/ -lLogic
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/Logic/debug/ -lLogic
INCLUDEPATH += $$PWD/Logic
DEPENDPATH += $$PWD/Logic
- En caso de que tengas todo en un solo proyecto de Qt :
En este caso, utilizar Subdirs
es una buena idea para separar los módulos de código entre sí. De esta forma puede tener módulos de software independientes que sean reutilizables y puedan cambiarse fácilmente. También hace que el proyecto sea mucho más limpio y fácil de leer.
En este enfoque, los módulos pueden interactuar entre sí a través de señales y ranuras, lo que hace que los diferentes componentes sean completamente independientes y cambiar un módulo no requiere cambiar otras partes.
Qt Creator proporciona una buena automatización para que las partes se agraden entre sí. Puede hacer un proyecto de Subdir y agregar sus subproyectos a su archivo .pro:
TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS += /
Component1 /
Component2 /
Component3 /
MainApp /
Debe traer los subproyectos de los que otros dependen, primero en la lista. También observe que el nombre del archivo .pro del subproyecto debe ser el mismo que su nombre de carpeta. De esta forma, los subproyectos se detectan y enumeran en el panel Proyectos.
Los subproyectos Component1
, Component2
y Component3
podrían ser bibliotecas. Parte del archivo .pro para Component1
:
TARGET = Component1
TEMPLATE = lib
DEFINES += COMPONENT1_LIBRARY
SOURCES += ...
HEADERS += ...
El subproyecto MainApp
puede ser una aplicación. Parte del archivo .pro para MainApp
:
TARGET = MainApp
TEMPLATE = app
Puede usar las bibliotecas de cada subproyecto al vincularlo al subproyecto. Esto se puede hacer haciendo clic derecho en el subproyecto y seleccionando "Agregar biblioteca" y luego "Biblioteca interna". Cuando selecciona una biblioteca de la lista de subproyectos, las configuraciones de enlace se agregan al .pro automáticamente. Será como:
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../Component1/release/ -lComponent1
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../Component1/debug/ -lComponent1
else:unix: LIBS += -L$$OUT_PWD/../Component1/ -lComponent1
INCLUDEPATH += $$PWD/../Component1
DEPENDPATH += $$PWD/../Component1
Bienvenido a SO.
Realmente has agrupado dos o tres preguntas aquí, pero vamos a intentarlo:
Como tercer componente, necesito algún tipo de control que vincule la lógica de la aplicación con su GUI.
Como está utilizando Qt, tiene una respuesta integrada a esta pregunta:
Qt Project-Model / View Programming . Para empezar:
La arquitectura del modelo / vista
Model-View-Controller (MVC) es un patrón de diseño que se origina en Smalltalk y que a menudo se utiliza al construir interfaces de usuario. En los patrones de diseño, Gamma et al. escribir:
MVC consiste en 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 del usuario reacciona a la entrada del usuario. Antes de MVC, los diseños de la interfaz de usuario tendían a agrupar estos objetos. MVC los desacopla para aumentar la flexibilidad y la reutilización.
Si la vista y los objetos del controlador se combinan, el resultado es la arquitectura del modelo / vista. Esto aún separa la forma en que se almacenan los datos de la forma en que se presenta al usuario, pero proporciona un marco más simple basado en los mismos principios. Esta separación permite mostrar los mismos datos en varias vistas diferentes e implementar nuevos tipos de vistas, sin cambiar las estructuras de datos subyacentes. Para permitir el manejo flexible de la entrada del usuario, presentamos el concepto del delegado. La ventaja de tener un delegado en este marco es que permite personalizar la forma en que los elementos de datos se procesan y editan.
El modelo MVC, respaldado explícitamente por el marco QT (y posible de implementar con otros marcos GUI, aunque con más trabajo), es ampliamente aceptado como un grupo robusto y flexible de patrones de diseño que permite la administración y separación de las diversas capas de aplicaciones , de la manera en que estás pensando, por lo que estás en el camino correcto.
El segundo punto puede sonar un poco extraño, lo admito; para decirlo brevemente, mis objetivos son ...
La cuestión de cómo configurar sus proyectos de código fuente realmente no tiene nada que ver con la arquitectura de su aplicación per se, aunque estas áreas generalmente se cruzan de tal forma que una buena organización de proyectos facilita una implementación más sencilla de su arquitectura, y viceversa. Cómo organizas tu proyecto y sus diferentes bibliotecas y clases pueden depender no solo del proyecto en el que estás trabajando ahora, sino de los planes para proyectos futuros. Por ejemplo, como mencionó, es posible que desee diseñar ciertos componentes de GUI que puede usar para varias aplicaciones diferentes. Si es así, es posible que desee colocar sus módulos GUI en una biblioteca genérica reutilizable separada que pueda ser utilizada por muchas aplicaciones.
Sin embargo, ciertas reglas son aplicables en todos los ámbitos y son seguidas por los desarrolladores más experimentados. Aquí hay algunas grandes, hay muchas más:
Una clase principal y sus clases de amigos por unidad (archivo hpp / cpp).
Tenga mucho cuidado con lo que incluye en los archivos de encabezado y lo que deja en sus archivos CPP. Encontrará directrices aquí en SO y en cualquier buen libro de C ++ sobre este tema, que es bastante importante, particularmente en proyectos complejos. (Por lo que parece, por ejemplo, sus preguntas sobre cómo usar
#include
y "conectar las partes" en el código) necesita conocer mejor algunos de los fundamentos de la programación en C ++. Algunos libros excelentes están ahí fuera. puede encontrar listas aquí. C ++ Primer (5ª Edición) es uno de los mejores lugares para comenzar.Analice sus clases y bibliotecas en términos de su funcionalidad. La mayoría de IDES admite subcarpetas virtuales en su proyecto (no está seguro acerca de Code :: Blocks) para ayudar a mantener las cosas organizadas de esa manera. En realidad, esto entra en cuestiones fundamentales de diseño, no solo cómo diseñar el código en su proyecto.
Evite el acoplamiento apretado
En ingeniería de software, acoplamiento o dependencia es el grado en que cada módulo de programa se basa en cada uno de los otros módulos.
El acoplamiento generalmente se contrasta con la cohesión. El acoplamiento bajo a menudo se correlaciona con una alta cohesión y viceversa. El bajo acoplamiento es a menudo un signo de un sistema informático bien estructurado y un buen diseño, y cuando se combina con una alta cohesión, es compatible con los objetivos generales de alta legibilidad y facilidad de mantenimiento.
Haga un buen uso de los espacios de nombres , otra característica de gran lenguaje que ayuda a mantener las cosas modularizadas y organizadas.
En su caso, parece que le gustaría hacer es empaquetar su "lógica de aplicación" en una biblioteca, sus módulos genéricos de GUI en un segundo y luego un tercer ejecutable delgado, quizás simplemente conteniendo main()
y algunas líneas para pon en marcha las cosas y ciérralas cuando haya terminado - que inicia la aplicación Qt e inicia las clases en tus bibliotecas, que interactúan utilizando el modelo MVC y hacen el trabajo real de la aplicación. Tres módulos separados no son necesarios, aunque serán más "genéricos" y reutilizables "y más fáciles de mantener organizados de esa manera.
Realmente ha tocado una amplia variedad de temas con esta pregunta, y de nuevo, algunos de ellos están relacionados con los fundamentos de programación de C ++, no simplemente "separar la lógica de la aplicación de la GUI". Esperemos que esta respuesta te ayude a moverte en la dirección correcta.
Una nota importante: la programación de GUI es una rama de programación completa y no particularmente fácil. Hay especialistas en GUI y hay programadores que trabajan con GUI solo mínimamente. (Soy uno de este último grupo). Hay un sitio de SE llamado Experiencia de usuario que, aunque no trata la programación de la GUI per se, trata de cómo los usuarios interactúan con los sistemas, lo cual está directamente relacionado con las técnicas de programación de GUI. Entonces, cuando dices "Ahora que decidí aprender programación de GUI", sé que estás asumiendo un gran trabajo. Si no está realmente interesado en hacer de su especialidad la programación de GUI, debería considerar usar Wizards y soluciones GUI prefabricadas en lugar de hacerlo todo a mano. QtCreator proporciona algo de este tipo de soporte, al igual que Code :: Blocks. Si tiene la intención de hacer este negocio serio, también hay marcos comerciales disponibles. A menos que lo haga simplemente por el simple hecho de aprender, no se recomienda reinventar la rueda para un trabajo serio de programación comercial.