Понятие и основные вопросы о разделении логики (С++) и GUI (Qt)

Я закончил проект в C++. Это консольное приложение, созданное с помощью CodeBlocks. Хотя я считаю это не столь важным в рамках этого вопроса: приложение управляет данными о счетах и ​​клиентах небольшой компании. Программа завершена и может быть очень легко расширена консольным пользовательским интерфейсом (прямо сейчас я запускаю ее как программиста).

Теперь я решил изучить GUI-программирование с помощью Qt и QtCreator с помощью QtDesigner!

Не только потому, что обычная практика отделять логику от GUI при создании приложения GUI, я хочу реализовать свой проект на двух больших участках, а именно, логика и GUI. Вы уже знаете, что логическая часть завершена; у меня есть папка проекта с названием project, содержащая другую папку (проект CodeBlocks) project_logic, которая снова содержит несколько классов, поэтому заголовочные файлы и файлы реализации (и основные, что, конечно же, будет устаревшим, в конечном итоге). Он также содержит файлы из /, в которые программа читает/записывает. Он написан в "чистом" C++ и не использует ни одно из средств, предоставляемых Qt, и для меня важно, чтобы он оставался таким образом!

Теперь я добавил проект Qt project_gui в папку project и начал создавать графический интерфейс, реализуя только самые основные функции, такие как изменение между диалогами, закрытие приложения и т.д. Пока он знает ничего о его будущей стороне (project_logic).

В качестве третьего компонента мне нужен какой-то управляющий, который связывает логику приложения с его графическим интерфейсом. Вот мой концептуальный вопрос: как лучше всего объединить их в одном приложении?

Предложения

  • Так как project_logic может работать отдельно как консольное приложение, он уже предоставляет наиболее важные компоненты и функции управления. Это останется таким, потому что я хочу сохранить свою автономную функциональность. Тем более, что я совершенно не знаком с программированием GUI и/или через две недели, я мог бы создать еще один графический интерфейс для той же логики. Результатом будет то, что классы логической части включаются в источник GUI, как и любой другой заголовок, и используются для создания программы с полной функциональностью. Проверка ввода пользователя будет зависеть от части GUI. Логика программы в любом случае оставалась бы обновляемой.

  • Сделать GUI как можно более многоразовым; должен ли я реализовать третий компонент à la project_controlling, который обеспечивает взаимодействие между графическим интерфейсом и логикой (подтверждение ввода пользователем, выполняемое посредством управления), в том, что каждый из двух остается как можно более независимым? GUI не включает в себя заголовки логики, так сказать, но включая контрольные заголовки?


Вторая точка может показаться немного странной, я признаю; Короче говоря, мои цели:

  • Сохранение стандартного project_logic C++ и независимого (с точки зрения исправления, добавления функций и т.д.) и
  • с использованием Qt для GUI при максимальном (в то же время разумном) разделении GUI и логики.

Поезда мысли

  • Должен ли я включать заголовки project_logic через #include "../project_logic/header1.h" и т.д.? (Может возникнуть проблема с использованием классов, которые я опубликую в отдельном вопросе.)

  • Должен ли я включать их в качестве подпроекта?

  • Как мне соединить детали "в коде"?

  • Выполняют ли логические функции файлы, о которых я упоминал ранее (чтение/запись)?


Пожалуйста, помните следующее: я новичок в программировании GUI! И я изо всех сил пытался объяснить свои мысли/проблемы... Однако я знаю C и С++ и пишу консольные приложения, которые я использую, например, симуляции в университете и вполне могут справиться со стандартными вещами, я считаю. Даже если потенциальный ответчик чувствует, что предлагает совершенно другой подход, я был бы признателен за "решение" за предложенную мной концепцию. Причина этого я объяснил во введении. Ненужно упомянуть, хотя я, конечно, заинтересован в том, чтобы слышать разные предложения.

Я решил опубликовать этот вопрос после того, как сделал некоторые исследования, и попытался изо всех сил попробовать "проб и ошибок". Существует много информации об этой теме на StackOverflow и других платах, поэтому я хотел представить свою идею и собрать критику и материалы, вместо того, чтобы добавлять другие "как?". к мешанине вопросов.

Поскольку этот вопрос касается общего подхода, я, может быть, (совершенно уверен...: -P) задаю более технические вопросы позже, которые я хотел бы отредактировать в этом вопросе (гиперссылки), как только они возникнут. Однако основные рецепты в этом вопросе, если они есть, приветствуются, конечно.


После некоторых комментариев и ответов я чувствую, что размещаю немного EDIT, чтобы все было ясно:

Текущее состояние логики

  • project_logic более или менее закончен и закодирован в CodeBlocks как проект CodeBlocks.
  • Он может работать как консольное приложение с "консольным пользовательским интерфейсом". (Он имеет main.cpp, который теперь используется только для отладки.)
  • Его компоненты по возможности разделяются на классы (заголовки и файлы реализации cpp).

Текущее состояние GUI

  • project_gui настраивается как проект Qt-Widget-Application (с использованием QtCreator/Designer).
  • Пока это только графический интерфейс не более (без связи с project_logic).

Цели и...

... рабочий процесс, я хочу следовать, так как это мой первый большой проект:

  • project_logic и project_gui не оставят своих соответствующих каталогов; они оба находятся в каталоге с именем project. (Исключение: логика будет экспортироваться как DLL (или что-то подобное), если это необходимо, которая затем предоставляется графическому интерфейсу.)
  • Если в project_logic есть вещи, которые нужно изменить, я хочу сделать это в CodeBlocks (и повторить возможный экспорт, как описано выше).
  • project_logic (или любой третий слой, например, project_controlling), нужно сделать одноразовым для project_gui самым простым способом, который можно вообразить... (см. Поезда мысли №1):-P

Ответы

Ответ 1

  • Если у вас есть отдельные проекты:

когда вы разработали разные части приложения в разных проектах, самый простой способ - просто связать свой основной проект с библиотеками и использовать их. Поэтому в вашем случае вы должны предоставить DLL для логики проекта, которая разработана и скомпилирована в CodeBlocks в ваш проект Qt, ссылается на нее и использует классы.

Например, вы можете поместить файлы заголовков вашей библиотеки в папку с именем Logic, а также отлаживать и выпускать версии файлов .lib в соответствующих папках и связывать ваше приложение:

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
  • Если у вас есть все в одном проекте Qt:

В этом случае использование Subdirs - это хорошая идея отделить модули кода друг от друга. Таким образом, вы можете иметь независимые программные модули, которые могут быть повторно использованы и могут быть легко изменены. Это также делает проект более чистым и более легким для чтения.

В этом подходе модули могут взаимодействовать друг с другом через сигналы и слоты, которые делают разные компоненты полностью независимыми, а изменение одного модуля не требует изменения других частей.

Qt Creator обеспечивает хорошую автоматизацию в отношении частей друг к другу. Вы можете создать проект Subdirs и добавить свои подпроекты в его .pro файл:

TEMPLATE = subdirs

CONFIG += ordered

SUBDIRS += \
    Component1 \
    Component2 \
    Component3 \
    MainApp \

Вы должны принести подпроекты, от которых зависят другие, сначала в списке. Также обратите внимание, что имя .pro файла подпроекта должно совпадать с именем папки. Таким образом, подпроекты обнаруживаются и отображаются на панели "Проекты".

Подпроекты Component1, Component2 и Component3 могут быть библиотеками. Часть файла .pro для Component1:

TARGET = Component1
TEMPLATE = lib

DEFINES += COMPONENT1_LIBRARY

SOURCES += ...
HEADERS += ...

Подпроект MainApp может быть приложением. Часть файла .pro для MainApp:

TARGET = MainApp
TEMPLATE = app

Вы можете использовать библиотеки в каждом подпроекте, связав его с подпроектом. Это можно сделать, щелкнув правой кнопкой мыши по подпроекту и выбрав "Добавить библиотеку", а затем "Внутренняя библиотека". Когда вы выбираете одну библиотеку из списка подпроектов, конфигурации ссылок автоматически добавляются в .pro. Это будет выглядеть так:

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

Ответ 2

Добро пожаловать в SO.

Вы действительно собрали два или три вопроса вместе, но давайте поупражняться:

В качестве третьего компонента мне нужен какой-то контроль, который связывает логики приложения с его графическим интерфейсом.

Поскольку вы используете Qt, у вас есть встроенный ответ на этот вопрос:

Qt Project-Model/Просмотр программирования. Чтобы начать работу:

Архитектура модели/представления

Model-View-Controller (MVC) - это шаблон проектирования, созданный из Smalltalk, который часто используется при создании пользовательских интерфейсов. В дизайне Шаблоны, Гамма и др. написать:

MVC состоит из трех видов объектов. Модель - это приложение объект, представление представляет собой его экранную презентацию, а контроллер определяет способ взаимодействия пользовательского интерфейса с пользовательским вводом. До MVC, проекты пользовательского интерфейса имеют тенденцию объединять эти объекты вместе. MVC отделяет их, чтобы повысить гибкость и повторное использование.

Если объекты представления и контроллера объединены, результатом является модель/представление архитектуры. Это все еще отделяет способ передачи данных хранится так, как он представляется пользователю, но обеспечивает более простую основу, основанную на тех же принципах. Это разделение делает он может отображать одни и те же данные в нескольких разных точках зрения и для реализации новых типов представлений без изменения исходных данных структур. Чтобы обеспечить гибкую обработку ввода пользователя, введем концепция делегата. Преимущество наличия делегата в этом является то, что он позволяет способ отображения элементов данных и отредактирован для настройки.

Модель MVC, явно поддерживаемая платформой QT (и возможная реализация с другими платформами графического интерфейса, а также с большей работой), широко признана в качестве надежной гибкой группы шаблонов проектирования, которая обеспечивает управление и разделение различные уровни приложений, в том виде, в котором вы думаете, - так что вы на правильном пути.

Вторая точка может показаться немного странной, я признаю; поставить Короче, мои цели...

Вопрос о том, как настроить проекты с исходным кодом, действительно не имеет ничего общего с архитектурой вашего приложения, хотя эти области обычно пересекаются, так что хорошая организация проекта облегчает реализацию вашей архитектуры и наоборот. Как вы организуете свой проект, его различные библиотеки и классы могут зависеть не только от проекта, над которым вы сейчас работаете, но и от планов будущих проектов. Например, как вы упомянули, вы можете захотеть создать определенные компоненты графического интерфейса, которые вы можете использовать для нескольких разных приложений. Если это так, вы можете захотеть поместить свои модули графического интерфейса в отдельную многоразовую общую библиотеку, которая может использоваться многими приложениями.

Некоторые правила, однако, применимы по всем направлениям, за которыми следуют самые опытные разработчики - вот несколько крупных, есть еще много:

  • Один крупный класс и его классы друзей на единицу (файл hpp/cpp).

  • Будьте очень осторожны с тем, что вы включаете в заголовочные файлы, и тем, что вы оставляете в своих файлах CPP. Ты найдешь руководящие принципы здесь о SO и в любой хорошей С++ книге по этому вопросу, которая что очень важно, особенно в сложных проектах. (Из звука это - например, ваши вопросы о том, как использовать #include и "соединить компоненты" в коде - вам нужно лучше понять некоторые основы программирования на С++. Там есть отличные книги - вы можете найти списки здесь. С++ Primer (5-й Edition) является одним из лучших мест для начала.)

  • Разбивайте свои классы и библиотеки с точки зрения их функциональность. Большинство IDES поддерживают виртуальные подпапки в вашем проекте (не уверены в Code:: Blocks), чтобы помочь организовать мероприятия в таких манера. Это фактически затрагивает фундаментальные вопросы проектирования, а не просто как выложить код в своем проекте.

  • Избегайте жесткая связь!

    В разработке программного обеспечения связь или зависимость - это степень, в которой каждый программный модуль полагается на каждый из других модулей.

    Связывание обычно противопоставляется сплоченности. Низкое сцепление часто коррелирует с высокой связностью и наоборот. Низкое сцепление часто является знак хорошо структурированной компьютерной системы и хороший дизайн, и когда в сочетании с высокой сплоченностью, поддерживает общие цели высоких читабельности и ремонтопригодности.

  • Использовать пространства имен, еще одна отличная языковая функция, которая помогает сохранять модульность и организованность.

В вашем случае кажется, что вы, возможно, захотите сделать, это упаковать свою "логику приложения" в одну библиотеку, ваши общие графические модули - на второй, а затем на третий, тонкий исполняемый файл, возможно, просто содержащий main() и несколько строк, чтобы отбросить и выключить их, когда это будет сделано - запускает приложение Qt и инициализирует классы в ваших библиотеках, которые взаимодействуют с использованием модели MVC и выполняют фактическую работу приложения. Три отдельных модуля не нужны, хотя они будут более "универсальными" и многоразовыми ", и их проще организовать таким образом.

Вы действительно затронули широкий круг вопросов с этим вопросом, и снова некоторые из них связаны с основами программирования на С++, а не просто "отделяют логику приложений от GUI". Надеюсь, этот ответ поможет вам двигаться в правильном направлении.

Важное замечание: GUI-программирование - это полная и не очень простая ветвь программирования. Есть специалисты GUI, и есть программисты, которые работают с GUI только минимально. (Я одна из последних групп). Существует SE-сайт под названием Пользовательский опыт, который, хотя он и не имеет дело с графическим интерфейсом , имеет дело с тем, как пользователи взаимодействуют с системами, который напрямую связан с методами программирования GUI. Итак, когда вы говорите: "Теперь я решил изучить программы GUI", знайте, что вы занимаетесь большой работой. Если вы не очень заинтересованы в программировании GUI своей специальности, вы можете рассмотреть возможность использования Wizards и готовых графических решений вместо того, чтобы делать все это вручную. QtCreator предоставляет некоторую такую ​​поддержку, как и Code:: Blocks. Если вы намерены заниматься этим серьезным бизнесом, есть и коммерческие рамки. Если вы не делаете это просто ради обучения, повторно изобретать колесо не рекомендуется для серьезных коммерческих программ.