6. Слой источников данных - MaxCiv/LibraryArchitecture GitHub Wiki

Для реализации слоя источников данных используется реляционная база данных. В качестве СУБД выбрана система MySQL. Для подключения к базе данных в исходном коде используется синглтон-класс DataGateway. Данный класс содержит параметры подключения к базе данных, подключается к ней и предоставляет всем остальным классам слоя источника данных доступ к БД.

Для отображения объектов программы в таблицы БД были использованы следующие структурные паттерны источников данных:

  • Поле идентификации (Identity Field) — каждый класс имеет поле id, которое позволяет идентифицировать экземпляры объектов этого класса. Данное поле является автогенерируемым (средствами БД);
  • Отображение внешних ключей (Foreign Key Mapping) — внутренние ссылки объектов друг на друга отображаются в БД в качестве внешних ключей.

База данных имеет следующий вид:

В качестве шлюза к слою используется интерфейс Repository, который реализует паттерн "Репозиторий". Это посредник между уровнями области определения (хранилище) и распределения данных. Использует интерфейс, похожий на коллекции, для доступа к объектам области определения. Репозиторий инкапсулирует набор объектов, сохраняемых в хранилище данных, и операции выполняемые над ними, обеспечивая более объектно-ориентированное представление реальных данных. Репозиторий также преследует цель достижения полного разделения и односторонней зависимости между уровнями области определения и распределения данных.

Интерфейс Repository (пакет storage) определяет следующие методы:

  • User logInUser(String login, String realPassword) — выполнить авторизацию пользователя;
  • User findUserById(int id) — найти пользователя по id;
  • User findUserByLogin(String login) — найти пользователя по логину;
  • Book findBookById(int id) — найти книгу по id;
  • List<Book> getAllBooks() — получить список всех книг;
  • List<BookBorrow> getAllBorrows() — получить список всех выдачей книг читателям;
  • List<BookBorrow> getAllUserBorrows(Reader reader) — получить список всех выдачей книг читателю с id;
  • List<BookExchange> getAllExchanges() — получить список всех обменов книг читателями;
  • List<BookExchange> getAllUserExchanges(Reader reader) — получить список всех обменов книг читателя с id;
  • List<BookOrder> getAllOrderings() — получить список всех заказов книг поставщикам;
  • List<BookOrder> getAllUserOrderings(Supplier supplier) — получить список всех заказов книг поставщика с id;
  • List<BookRecord> getAllRequireConfirmation() — получить список всех выдачей книг читателям, требующих подтверждения от библиотекаря;
  • List<User> getAllUsers() — получить список всех пользователей;
  • void addNewUser(User newUser) — добавить нового пользователя;
  • void addNewBook(Book book) — добавить новую книгу;
  • void addNewBookBorrow(BookBorrow bookBorrow) — добавить новую выдачу книги;
  • void openNewExchange(BookExchange bookExchange) — открыть новый обмен;
  • void openNewOrder(BookOrder bookOrder) — открыть новый заказ;
  • void update(Object obj) — обновить объект;
  • void updateAll() — обновить все объекты;
  • void clearAll() — очистить весь кэш объектов;
  • void dropAll() — очистить базу данных.

Для создания слоя источников данных используется архитектурный паттерн "Преобразователь данных" (Data Mapper). Для всех классов слоя бизнес-логики был создан свой преобразователь. Преобразователи данных позволяют иерархически считывать и обновлять данные в БД.

Каждый класс-преобразователь данных реализует интерфейс Mapper. Интерфейс объявляет следующие методы:

  • T findById(final int id) — найти объект в БД по идентификатору;
  • Map<Integer, T> findAll() — найти все объекты в БД;
  • void update(T item) — обновить объект;
  • void update() — обновить все объекты;
  • void closeConnection() — закрыть соединение с БД.

Как видно из методов интерфейса, каждый преобразователь данных так же имеет свой локальный кэш объектов, извлеченных из БД. При обращении к преобразователю за объектом, он сначала проверяет его наличие в кэше. Если объект найден в кэше, возвращается ссылка на него. Если объекта в кэше нет, то производится обращение к БД. Извлеченный из БД объект так же сразу добавляется в локальный кэш. Данное решение позволяет обеспечить, чтобы в каждый момент времени в системе существовал только один экземпляр какого-либо объекта. При этом, преобразователи данных при синхронизации с БД могут не обновлять некоторые элементы (например, если объект неизменяемый), что позволяет немного оптимизировать работу.

Все преобразователи находятся в пакете storage.mappers.

Для тестирования слоя источников данных написан JUnit тест MappersRepositoryTest (находится в модуле test, пакете storage), который проверяет все основные методы класса репозитория и преобразователей.

<< 5. Слой бизнес-логики | 7. Сервисный слой >>

⚠️ **GitHub.com Fallback** ⚠️