Перейти к содержанию

Компоненты: абстрактные классы

Эта страница описывает роль и устройство абстрактных классов в архитектуре QTasks. Абстрактные классы формируют контракты компонентов и являются ключевым механизмом согласованности всей системы.

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


Роль абстрактных классов

Каждый основной и дополнительный компонент QTasks обязан наследоваться от соответствующего абстрактного класса. Эти классы:

  • задают контракт взаимодействия компонента с системой;
  • фиксируют обязательные методы и их сигнатуры;
  • определяют модель синхронного и асинхронного выполнения;
  • служат единым источником документации и типизации.

Если компонент не реализует обязательный метод, объявленный через @abstractmethod, его создание приводит к ошибке на уровне Python, ещё до запуска системы.


Базовое именование

Все абстрактные классы компонентов следуют единому шаблону именования:

  • Base<Component> — абстрактный класс;
  • (A)sync<СпособРаботы><Component> — конкретная реализация.

Пример:

  • BaseStorage — контракт компонента хранения;
  • AsyncRedisStorage — асинхронная реализация хранилища на базе Redis.

Такое именование делает архитектуру самодокументируемой и позволяет сразу определить роль и модель выполнения компонента.


Разделение на Async и Sync

Абстрактные классы используют параметризацию через Generic[TAsyncFlag] для строгого разделения синхронных и асинхронных компонентов.

  • TAsyncFlag = True — асинхронный компонент;
  • TAsyncFlag = False — синхронный компонент.

Это разделение отражается в типах методов через @overload, например:

  • self: BaseBroker[Literal[True]] — асинхронный контекст;
  • self: BaseBroker[Literal[False]] — синхронный контекст.

Архитектурное правило:

  • асинхронные компоненты могут работать с синхронными функциями;
  • синхронные компоненты не допускают вызова асинхронных функций.

Это ограничение намеренно жёсткое и предотвращает неявные ошибки исполнения.


Конструктор компонента

Каждый абстрактный класс определяет собственный __init__, через который проходит инициализация компонента.

Через конструктор:

  • передаются обязательные зависимости;
  • задаются параметры конфигурации;
  • фиксируются инварианты компонента.

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


Обязательные методы и поведение по умолчанию

Абстрактные классы в QTasks могут содержать:

  • методы, помеченные @abstractmethod, которые обязаны быть реализованы;
  • методы с реализацией по умолчанию;
  • вспомогательные методы, используемые внутри компонента.

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


Документация и типизация

Каждый метод в абстрактных классах сопровождается документацией в формате Google docstring.

Это обеспечивает:

  • единый стиль документации во всём QTasks;
  • синхронизацию архитектурного описания и кода;
  • корректную работу IDE, статического анализа и автодополнения.

Абстрактный класс является каноническим источником информации о том, как компонент должен себя вести.


Абстрактные классы плагинов

Та же архитектурная модель применяется и к плагинам.

  • базовый класс плагинов: BasePlugin;
  • конкретные реализации следуют тому же шаблону (A)sync<СпособРаботы>Plugin.

Пример:

  • BasePlugin;
  • AsyncPydanticWrapperPlugin.

Это обеспечивает единообразие между компонентами и плагинами и упрощает их совместное использование.


Архитектурные инварианты

  • любой компонент обязан наследоваться от Base<Component>;
  • несоблюдение контракта приводит к ошибке на этапе создания класса;
  • разделение Async/Sync фиксируется на уровне типов;
  • документация и типизация являются частью контракта.

Эти правила делают архитектуру QTasks строгой, предсказуемой и расширяемой без скрытых соглашений.