Files
new_lottery_bot/src/container.py
Andrey K. Choi 4a741715f5
Some checks reported errors
continuous-integration/drone/push Build encountered an error
feat: Полный рефакторинг с модульной архитектурой
- Исправлены критические ошибки callback обработки
- Реализована модульная архитектура с применением SOLID принципов
- Добавлена система dependency injection
- Создана новая структура: interfaces, repositories, components, controllers
- Исправлены проблемы с базой данных (добавлены отсутствующие столбцы)
- Заменены заглушки на полную функциональность управления розыгрышами
- Добавлены отчеты о проделанной работе и документация

Архитектура готова для production и легко масштабируется
2025-11-17 05:34:08 +09:00

120 lines
4.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Dependency Injection Container для управления зависимостями
Следует принципам SOLID, особенно Dependency Inversion Principle
"""
from typing import Dict, Any, TypeVar, Type
from sqlalchemy.ext.asyncio import AsyncSession
from src.interfaces.base import (
IUserRepository, ILotteryRepository, IParticipationRepository, IWinnerRepository,
ILotteryService, IUserService, IBotController, IKeyboardBuilder, IMessageFormatter
)
from src.repositories.implementations import (
UserRepository, LotteryRepository, ParticipationRepository, WinnerRepository
)
from src.components.services import LotteryServiceImpl, UserServiceImpl
from src.components.ui import KeyboardBuilderImpl, MessageFormatterImpl
from src.controllers.bot_controller import BotController
T = TypeVar('T')
class DIContainer:
"""Контейнер для dependency injection"""
def __init__(self):
self._services: Dict[Type, Any] = {}
self._singletons: Dict[Type, Any] = {}
# Регистрируем singleton сервисы
self.register_singleton(IKeyboardBuilder, KeyboardBuilderImpl)
self.register_singleton(IMessageFormatter, MessageFormatterImpl)
def register_singleton(self, interface: Type[T], implementation: Type[T]):
"""Зарегистрировать singleton сервис"""
self._services[interface] = implementation
def register_transient(self, interface: Type[T], implementation: Type[T]):
"""Зарегистрировать transient сервис"""
self._services[interface] = implementation
def get_singleton(self, interface: Type[T]) -> T:
"""Получить singleton экземпляр"""
if interface in self._singletons:
return self._singletons[interface]
if interface not in self._services:
raise ValueError(f"Service {interface} not registered")
implementation = self._services[interface]
instance = implementation()
self._singletons[interface] = instance
return instance
def create_scoped_container(self, session: AsyncSession) -> 'ScopedContainer':
"""Создать scoped контейнер для сессии базы данных"""
return ScopedContainer(self, session)
class ScopedContainer:
"""Scoped контейнер для одной сессии базы данных"""
def __init__(self, parent: DIContainer, session: AsyncSession):
self.parent = parent
self.session = session
self._instances: Dict[Type, Any] = {}
def get(self, interface: Type[T]) -> T:
"""Получить экземпляр сервиса"""
# Если это singleton, получаем из родительского контейнера
if interface in [IKeyboardBuilder, IMessageFormatter]:
return self.parent.get_singleton(interface)
# Если уже создан в текущем scope, возвращаем
if interface in self._instances:
return self._instances[interface]
# Создаем новый экземпляр
instance = self._create_instance(interface)
self._instances[interface] = instance
return instance
def _create_instance(self, interface: Type[T]) -> T:
"""Создать экземпляр с разрешением зависимостей"""
if interface == IUserRepository:
return UserRepository(self.session)
elif interface == ILotteryRepository:
return LotteryRepository(self.session)
elif interface == IParticipationRepository:
return ParticipationRepository(self.session)
elif interface == IWinnerRepository:
return WinnerRepository(self.session)
elif interface == ILotteryService:
return LotteryServiceImpl(
self.get(ILotteryRepository),
self.get(IParticipationRepository),
self.get(IWinnerRepository),
self.get(IUserRepository)
)
elif interface == IUserService:
return UserServiceImpl(
self.get(IUserRepository)
)
elif interface == IBotController:
return BotController(
self.get(ILotteryService),
self.get(IUserService),
self.get(IKeyboardBuilder),
self.get(IMessageFormatter),
self.get(ILotteryRepository),
self.get(IParticipationRepository)
)
else:
raise ValueError(f"Cannot create instance of {interface}")
# Глобальный экземпляр контейнера
container = DIContainer()