Я работаю в архитектуре, она собирается предложить API отдыха для веб-клиента и мобильных приложений. Я использую Spring (Spring MVC, Spring данных JPA, ... и т. Д.). Модель предметной области закодирована со спецификацией JPA.
Я пытаюсь применить некоторые концепции чистой архитектуры ( https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html ). Не все, потому что я собираюсь сохранить модель домена jpa.
Фактический поток через слои таков:
Внешний интерфейс <-> Служба API -> Служба -> Репозиторий -> БД
- Внешний интерфейс: веб-клиент, мобильные приложения
- API Service : Rest Controllers, здесь я использую конвертеры и сервисы dto's и call
- Сервис : Интерфейсы с реализациями, и они содержат бизнес-логику
- Репозиторий : интерфейсы репозитория с автоматическими реализациями (выполняемыми Spring data jpa), которые содержат операции CRUD и, возможно, некоторые SQL-запросы.
Мое сомнение: я должен использовать дополнительный слой между службой и хранилищем?
Я планирую этот новый поток:
Внешний интерфейс <-> Служба API -> Служба -> Постоянство -> Репозиторий -> БД
Зачем использовать этот постоянный слой? Как говорится в статье о чистой архитектуре, я хотел бы иметь реализацию службы (бизнес-логика или сценарий использования), которая имеет доступ к слою постоянства. И никакие изменения не потребуются, если я решу использовать другой шаблон «доступа к данным», например, если я решу прекратить использование репозитория.
class ProductServiceImpl implements ProductService {
ProductRepository productRepository;
void save(Product product) {
// do business logic
productRepository.save(product)
}
}
Так что я думаю использовать постоянный слой, подобный этому:
class ProductServiceImpl implements ProductService {
ProductPersistence productPersistence;
void save(Product product) {
// do business logic
productPersistence.save(product)
}
}
и реализация персистентного слоя, как это:
class ProductPersistenceImpl implements ProductPersistence {
ProductRepository productRepository;
void save(Product product) {
productRepository.save(product)
}
}
Поэтому мне нужно только изменить реализации уровня персистентности, оставив сервис без изменений. В сочетании с тем, что репозиторий связан с фреймворком.
Что вы думаете? Спасибо.
источник
Ответы:
Правильно. Это базовый дизайн по разделению проблем, предложенных Spring Framework. Значит, вы находитесь на « весне правильным путем ».
Несмотря на то, что репозитории часто используются в качестве DAO, правда в том, что разработчики Spring взяли понятие Repository от DDD Эрика Эванса. Интерфейсы репозитория часто выглядят очень похожими на DAO из-за методов CRUD и потому, что многие разработчики стремятся сделать интерфейсы репозиториев настолько обобщенными, что, в конце концов, они не имеют различий с EntityManager (истинный DAO здесь) 1, но поддерживают запросы и критерии.
В переводе на компоненты Spring ваш дизайн похож на
Репозиторий уже является абстракцией между сервисами и хранилищами данных. Когда мы расширяем интерфейсы репозитория Spring Data JPA, мы реализуем этот проект неявно. Когда мы делаем это, мы платим налог: тесная связь с компонентами Spring. Кроме того, мы разбиваем LoD и YAGNI, наследуя несколько методов, которые нам могут не понадобиться или которые мы не хотим иметь. Не говоря уже о том, что такой интерфейс не дает нам какой-либо ценной информации о потребностях домена, которые они обслуживают.
При этом расширение репозиториев Spring Data JPA не является обязательным, и вы можете избежать этих компромиссов, внедрив более простую и настраиваемую иерархию классов.
Изменение источника данных теперь требует новой реализации, которая заменяет EntityManager другим источником данных .
и так далее. 2
Возвращаясь к вопросу о том, следует ли вам добавить еще один слой абстракции, я бы сказал, что нет, поскольку в этом нет необходимости. Ваш пример только добавляет больше сложности. Слой, который вы предлагаете, в конечном итоге станет прокси между сервисами и репозиториями или слоем псевдо-сервисов-репозиториев, когда нужна конкретная логика, а вы не знаете, где ее разместить.
1: В отличие от многих разработчиков, интерфейсы репозитория могут полностью отличаться друг от друга, потому что каждый репозиторий обслуживает разные потребности домена. В Spring Data JPA роль DAO играет EntityManager . Он управляет сессий, доступ к DataSource , отображения и т.д.
2: аналогичное решение улучшает интерфейсы репозитория Spring, смешивая их с пользовательскими интерфейсами. Для получения дополнительной информации ищите BaseRepositoryFactoryBean и @NoRepositoryBean . Тем не менее, я нашел этот подход громоздким и запутанным.
источник
Лучший способ доказать гибкость дизайна - это согнуть его.
Вам нужно место в вашем коде, которое отвечает за постоянство, но не связано с идеей использования репозитория. Хорошо. В данный момент он не делает ничего полезного ... вздох, хорошо.
Хорошо, давайте проверим, хорошо ли этот шунтирующий слой. Создайте слой плоского файла, который сохранит ваши продукты в файлах. Теперь, где этот новый слой идет в этом дизайне?
Ну, это должно быть в состоянии пойти, где БД. В конце концов, нам больше не нужна БД, поскольку мы используем плоские файлы. Но для этого также не требовалось хранилище.
Подумайте, может быть, репозиторий - это деталь реализации. В конце концов я могу общаться с БД без использования шаблона хранилища.
Если вы можете заставить все это работать, не касаясь Сервиса, у вас есть гибкий код.
Но не верьте мне на слово. Напишите это и посмотрите, что произойдет. Единственный код, которому я доверяю, это гибкий код.
источник