Ответ
Паттерн Репозиторий (Repository) выступает в роли посредника между доменной логикой (бизнес-логикой) и слоем доступа к данным (например, базой данных, API, файловой системой). Его основная задача — создать абстракцию над хранилищем, предоставляя интерфейс для работы с данными, как с обычной коллекцией объектов в памяти.
Ключевые цели и преимущества:
- Изоляция от источника данных: Бизнес-логика не знает, откуда берутся данные — из SQL-базы, NoSQL-хранилища или внешнего API. Это позволяет легко заменять источник данных без изменения основного кода.
- Централизация логики запросов: Все запросы к данным (фильтрация, сортировка, выборка) инкапсулируются внутри репозитория, что предотвращает их дублирование по всему приложению.
- Упрощение тестирования: Бизнес-логику можно тестировать изолированно, подменив реальный репозиторий на mock-объект (in-memory реализацию), который не требует подключения к базе данных.
- Повышение читаемости кода: Код сервисного слоя становится чище, так как вместо SQL-запросов или вызовов ORM он оперирует понятными методами, например,
user_repository.get_by_email(email)
.
Упрощенный пример на Python:
from abc import ABC, abstractmethod
from dataclasses import dataclass
# Модель данных (доменный объект)
@dataclass
class User:
id: int
username: str
# Абстрактный репозиторий (интерфейс)
class AbstractUserRepository(ABC):
@abstractmethod
def get_by_id(self, user_id: int) -> User | None:
raise NotImplementedError
@abstractmethod
def add(self, user: User) -> None:
raise NotImplementedError
# Конкретная реализация для работы с БД (например, PostgreSQL)
class PostgresUserRepository(AbstractUserRepository):
def __init__(self, db_connection):
self.connection = db_connection
def get_by_id(self, user_id: int) -> User | None:
# Здесь будет реальный SQL-запрос
print(f"[DB] Получение пользователя с id={user_id} из PostgreSQL")
# cursor.execute("SELECT id, username FROM users WHERE id = %s", (user_id,))
# ... логика получения данных
if user_id == 1:
return User(id=1, username="john_doe")
return None
def add(self, user: User) -> None:
print(f"[DB] Добавление пользователя {user.username} в PostgreSQL")
# cursor.execute("INSERT INTO ...")
# Сервисный слой, который использует репозиторий
class UserService:
def __init__(self, user_repo: AbstractUserRepository):
self.user_repo = user_repo
def find_user(self, user_id: int):
user = self.user_repo.get_by_id(user_id)
if user:
return f"Найден пользователь: {user.username}"
return "Пользователь не найден"
# Использование
db_conn = "..." # Условное подключение к БД
repo = PostgresUserRepository(db_conn)
service = UserService(repo)
print(service.find_user(1))