Основные положения
Интерфейс загрузки плагинов и моделей должен быть минимальным.
- Плагин может:
-
- Зарегистрировать свои модели.
- Получить чужие модели.
- Корректно завершить работу при запросе ядра.
- Хост отвечает за:
-
- Поиск и загрузку модулей (плагинов).
- Порядок инициализации.
- Жизненный цикл моделей и модулей (плагинов).
Вся функциональность, доступная другим модулям, публикуется через модели (динамические библиотеки).
Модель — контейнер и интерфейс
Модель — это одновременно контейнер и интерфейс взаимодействия.
- Контейнер
- Модель может хранить общие (shared) данные, не являясь провайдером функциональности какого‑либо плагина.
- Интерфейс
- Модель может быть провайдером функциональности и экспортировать методы одного или нескольких плагинов.
- Плагины не общаются напрямую; они знают только имена и типы моделей.
- Одна модель может агрегировать функциональность от нескольких модулей или выбирать активную реализацию.
- Смена реализации не требует изменений у потребителей, если интерфейс модели стабилен.
Паттерн many‑to‑many
Многие плагины могут получать функционал через одну модель от многих плагинов
Пример: InternalNetModel и транспорт
- "Бизнес"‑плагины работают только с InternalNetModel, не зная, какой транспорт реально используется.
- Провайдеры транспорта подгружаются как плагины и регистрируют себя внутри модели.
- Состав транспорта может динамически меняться: TLS, HTTPS, TCP, UDP — по набору доступных модулей.
InternalNetModel <--> InternalNetHttpsPlugin
InternalNetModel <--> InternalNetTlsPlugin
InternalNetModel <--> InternalNetTcpPlugin
InternalNetModel <--> InternalNetUdpPlugin
Пример: PayModel и платёжные системы
- PayModel задаёт единый интерфейс “запрос пополнения счёта” и обработку статусов.
- Каждый платёжный плагин регистрируется в PayModel и реализует конкретную интеграцию.
- Расширение списка провайдеров не требует новой версии всего комплекса — достаточно добавить новый модуль.
PayModel <--> PayFreeKassaPlugin
PayModel <--> PayYouMoneyPlugin
PayModel <--> PayWataPlugin
PayModel <--> Pay...Plugin
Паттерн many‑to‑one
Модель также можеть быть интерфейсом единственного возможного плагина‑провайдера. Если модуль не загрузился, модель сообщает об этом потребителям, а они сами решают, что делать дальше.
Пример: VirtualMachineManager
- VitualMachineManagerModel описывает операции управления ВМ, общие для всех потребителей.
- Реализация берётся из одного плагина: VitualMachineManagerPlugin или, при необходимости, из удалённой версии ExternalVitualMachineManagerPlugin.
- Одновременно может быть загружен только один плагин для реализации функционала VitualMachineManagerModel.
- Плагины‑потребители (панель, экспортёр метрик, онлайн‑сервис) завязаны только на модель и одинаково работают с локальной или удалённой реализацией.
VitualMachineManagerModel <--> VitualMachineManagerPlugin
VitualMachineManagerModel <--> ExternalVitualMachineManagerPlugin
Паттерн one‑to‑many
One‑to‑many — просто другая сторона предыдущих паттернов. Если модули спроектированы как независимые провайдеры через модели, можно брать готовый набор модулей и собирать вокруг него совершенно разные приложения.
- Один и тот же комплект модулей (логирование, транспорт, платёжная модель, управление ВМ) можно переиспользовать в нескольких продуктах.
- Различия между приложениями сводятся к конфигурации и наличию/отсутствию конкретных плагинов, а не к ответвлениям кода.
- Такой подход особенно полезен в экосистемах: разные утилиты или сервисы собираются из одного “ящика с кубиками”.