Объяснение шаблона проектирования репозитория
Раньше я работал с такими фреймворками, как SpringBoot, но я никогда не задумывался над причинами, лежащими в основе большинства конструкций. Только когда мне нужно было разработать API с нуля без использования каких-либо фреймворков, я понял ценность шаблонов проектирования, встроенных в фреймворки.
В этой статье мы обсудим шаблон репозитория. Репозиторий — это уровень абстракции поверх кода, который взаимодействует с уровнем данных (например, файловой системой, базой данных).
На практике репозиторий обычно состоит из класса с методами для выполнения операций CRUD в базе данных.
Например, предположим, что мы создали репозиторий для выполнения запросов к базе данных с помощью библиотеки Python SQLAlchemy.
class SqlAlchemyOrdersRepository: def __init__(self, session): self._session = session def add(self, order: Order): self._session.add(order) def find(self, **kwargs): return self._session.query(Order).filter_by(**kwargs).first() def find_all(self, **kwargs): return self._session.query(Order).filter_by(**kwargs).all() def delete(self, order: Order): self._session.delete(order)
Преимущество использования этой абстракции в остальной части нашей кодовой базы, а не выполнения функций непосредственно с использованием экземпляра Session, заключается в том, что мы можем легко заменить его чем-то другим, что, в свою очередь, упрощает тестирование кода.
Предположим, мы определили следующий сервис:
class MyService: self._repository = None def __init__(repository: SqlAlchemyOrdersRepository): self._repository = repository def add(order: Order): ... self._repository.add(order) ...
Затем мы можем создать абстрактный класс с теми же методами, что и SqlAlchemyOrdersRepository.
class AbstractOrdersRepository(abc.ABC): @abc.abstractmethod def find(self, **kwargs): raise NotImplementedError @abc.abstractmethod def add(self, order: Order): raise NotImplementedError @abc.abstractmethod def delete(self, order: Order): raise NotImplementedError @abc.abstractmethod def find_all(self, **kwargs): raise NotImplementedError
Мы делаем SqlAlchemyOrdersRepository наследником AbstractOrdersRepository.
class SqlAlchemyOrdersRepository(AbstractOrdersRepository): ...
Затем мы заменяем все ссылки на SqlAlchemyOrdersRepository на AbstractOrdersRepository.
class MyService: self._repository = None def __init__(repository: AbstractOrdersRepository): self._repository = repository def add(order: Order): ... self._repository.add(order) ...
Наконец, определяем подделку. Фальшивые объекты, в отличие от макетов, на самом деле имеют рабочие реализации, но обычно используют некоторые сокращения, которые делают их непригодными для производства (например, в базе данных памяти).
class FakeOrdersRepository(AbstractOrdersRepository): def __init__(self, orders: List[Order]): self._orders = set(orders) def find(self, **kwargs): for order in self._orders: if all(getattr(order, k) == v for k, v in kwargs.items()): return order return None def find_all(self, **kwargs): return [ order for order in self._orders if all(getattr(order, k) == v for k, v in kwargs.items()) ] def add(self, order: Order): self._orders.add(order) def delete(self, order: Order): self._orders.remove(order)
Теперь для того, чтобы написать автоматические тесты для логики, содержащейся в нашем сервисе, нам не нужно использовать интеграционные тесты, которые потребовали бы настройки базы данных. Вместо этого мы можем просто использовать модульные тесты.
class TestMyService: def test_add(): repository = FakeRepostiory([]) order = Order('id') my_service = MyService() my_service.add(order) assert repository._orders == [order] assert ...
Заворачивать
Репозиторий — это слой абстракции поверх кода, который взаимодействует со слоем данных. Репозиторий можно «подделать», чтобы тестировать код независимо от базы данных.
Повышение уровня кодирования
Спасибо, что являетесь частью нашего сообщества! Перед тем, как ты уйдешь:
- 👏 Хлопайте за историю и подписывайтесь на автора 👉
- 📰 Смотрите больше контента в публикации Level Up Coding
- 💰 Бесплатный курс собеседования по программированию ⇒ Просмотреть курс
- 🔔 Подписывайтесь на нас: Twitter | ЛинкедИн | "Новостная рассылка"
🚀👉 Присоединяйтесь к коллективу талантов Level Up и найдите прекрасную работу