Цели архитектуры Qt-проекта
Хороший Qt-проект:
- изолирует UI от бизнес-логики
- минимизирует зависимости между модулями
- легко тестируется без GUI
- собирается на всех платформах
- масштабируется до сотен таргетов
- допускает плагины
- интегрируется в CI/CD
CMake здесь — не просто билд-система, а средство описания архитектуры.
Слоистая структура (Layered Architecture)
Типовая схема:
app/ ├─ ui/ (Qt Widgets / QML) ├─ domain/ (бизнес-логика) ├─ services/ (сетевые/IO/БД) ├─ infrastructure/ ├─ plugins/ └─ tests/
Каждый слой — отдельная библиотека.
Модульность через targets
Root:
add_subdirectory(domain) add_subdirectory(services) add_subdirectory(ui) add_subdirectory(app)
domain/CMakeLists.txt:
add_library(domain STATIC
order.cpp
order.h
)
target_include_directories(domain PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(domain PUBLIC Qt6::Core)
ui:
add_library(ui STATIC mainwindow.cpp mainwindow.h)
target_link_libraries(ui
PRIVATE Qt6::Widgets
PUBLIC domain
)
app:
qt_add_executable(myapp main.cpp) target_link_libraries(myapp PRIVATE ui services)
Dependency Rule
UI → Services → Domain
Domain не знает о Qt Widgets.
Допустимо:
- QtCore
- std
Недопустимо:
- GUI
- Network UI
MVVM / MVP в Qt
Qt легко реализует MVVM:
View (QML) ↓ ViewModel (QObject) ↓ Domain
ViewModel — библиотека:
add_library(viewmodels STATIC user_vm.cpp) target_link_libraries(viewmodels PUBLIC domain Qt6::Core)
Plugins Architecture
Qt поддерживает runtime-плагины.
plugins/logger:
qt_add_plugin(logger_plugin) target_link_libraries(logger_plugin PRIVATE Qt6::Core)
Интерфейс:
class ILogger {
public:
virtual ~ILogger() = default;
virtual void log(QString msg) = 0;
};
Q_DECLARE_INTERFACE(ILogger, "org.example.Logger")
QML-модули как отдельные targets
qt_add_qml_module(gui
URI My.App.GUI
VERSION 1.0
QML_FILES Main.qml
)
Test-friendly архитектура
domain/tests:
add_executable(domain_tests test_order.cpp) target_link_libraries(domain_tests PRIVATE domain Catch2::Catch2WithMain) add_test(NAME domain COMMAND domain_tests)
Presets для Qt-проектов
{
"configurePresets": [
{
"name": "linux-debug",
"generator": "Ninja",
"binaryDir": "build/linux-debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"QT_QPA_PLATFORM": "offscreen"
}
}
]
}
Монорепозитории и superbuild
superbuild/ ├─ CMakeLists.txt └─ external/
Использование FetchContent:
FetchContent_Declare(
mylib
GIT_REPOSITORY ...
)
