Я создаю проект Spring Boot для работы. В этом проекте у меня есть служба, которой поручено получать определенные документы из другого бэкэнда. Существует довольно много различных сценариев, когда документы должны соответствовать определенным критериям, например. быть с определенной даты, которая может быть сопоставлена свободно. В настоящее время это выполняется обычным методом, например:
@Service
public class DocumentService(){
private OtherService otherService;
@Autowire
public DocumentService(OtherService otherService){
this.otherService = otherService;
}
public List<Document> getDocuments() {
...
}
public List<Document> getDocuments(LocalDate date) {
...
}
public List<Document> getDocuments(String name){
...
}
public List<Document> getDocuments(String name, LocalDate date){
...
}
}
Я считаю, что это довольно плохое решение, потому что для каждой новой комбинации должен быть новый метод. По этой причине я хотел бы использовать для этого свободный интерфейс стиля, что-то вроде этого:
//Some other class that uses DocumentService
documentService().getDocuments().withDate(LocalDate date).withName(String name).get();
Я знаком с Builder Pattern и цепочкой методов, но я не вижу способа, как я могу адаптировать любой из них. Поскольку, насколько я понимаю, классы @Service являются синглтонами в Spring Boot.
Возможно ли это вообще с Spring Boot?
Если вы хотите использовать здесь плавный интерфейс, объект, возвращаемый вашим методом getDocuments()
, должен быть отправной точкой для цепочки методов. Возможно, создайте что-то вроде класса DocumentFilter
, который вы можете оттуда вернуть, тогда вы получите что-то вроде этого:
documentService.documents().getDocuments().withDate(LocalDate date).withName(String name).getDocuments()
В этом примере ваш DocumentFilter
будет иметь методы withDate(...)
и withName(...)
, и каждый последующий вызов включает все критерии из предыдущего DocumentFilter
.
Это не обязательно должно быть решение Spring Boot, почему бы просто не ввести локальный класс, похожий на POJO Builder:
@Service
public class DocumentService(){
public Builder documents() {
return new Builder();
}
public class Builder {
private LocalDate date;
private String name;
public Builder withDate(LocalDate date) {
this.date = date;
return this;
}
// etc
public List<String> get() {
final List<SomeDTO> results = otherService.doQuery(name, date, ...);
// TODO - tranform DTO to List<String>
return list;
}
}
}
Очевидно, сделайте его статическим, если ему не нужен доступ к родительскому компоненту.
Вы можете сделать компонент Spring и сборщик одним и тем же объектом, но это кажется надуманным, также я ожидаю, что вы хотели бы иметь возможность поддерживать несколько сборщиков.
Также я предполагаю, что родительский компонент действительно является службой, то есть он не содержит никаких состояний или мутаторов, в противном случае вы создаете потенциальные проблемы с синхронизацией.
Обновлено: Просто для иллюстрации построитель поддерживает аргументы, которые должны быть переданы в otherService
, и выполняет любые сервисные преобразования.
Не рассматривайте это как проблему, нет, единственная причина, по которой я упомянул, заключается в том, что служба является одноэлементной, поэтому вам нужно знать о таких соображениях, но, конечно, это относится ко всем вашим компонентам (я не должен был путать вопрос !)
Не могли бы вы также подробнее рассказать о застройщике? Аргументы должны идти внутри класса строителя, верно? Также я должен просто выполнить логику внутри функции .get()
или передать конструктор классу @Service? Спасибо за уточнение части перед :)
@Puck Да, аргументы являются свойствами построителя. Я добавил немного больше иллюстраций, otherService
обрабатывается как ресурс данных DAO или spring (просто для примера), а метод get() выполняет некоторое преобразование результатов, которое часто требуется в службе. Надеюсь, это поможет. Вам, вероятно, придется подумать о проверке аргументов перед делегированием взаимодействующим компонентам.
Большое спасибо, так и будет. Я отметил ваш ответ как принятый.
Родительский компонент не имеет никакого состояния или чего-то подобного, но он ссылается на другие компоненты, см. пример кода, который я обновил. Это тоже будет проблемой?