Свободный интерфейс в Spring Boot Service

Я создаю проект 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?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
617
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Если вы хотите использовать здесь плавный интерфейс, объект, возвращаемый вашим методом 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, и выполняет любые сервисные преобразования.

Родительский компонент не имеет никакого состояния или чего-то подобного, но он ссылается на другие компоненты, см. пример кода, который я обновил. Это тоже будет проблемой?

Puck 11.12.2020 15:48

Не рассматривайте это как проблему, нет, единственная причина, по которой я упомянул, заключается в том, что служба является одноэлементной, поэтому вам нужно знать о таких соображениях, но, конечно, это относится ко всем вашим компонентам (я не должен был путать вопрос !)

stridecolossus 11.12.2020 15:56

Не могли бы вы также подробнее рассказать о застройщике? Аргументы должны идти внутри класса строителя, верно? Также я должен просто выполнить логику внутри функции .get() или передать конструктор классу @Service? Спасибо за уточнение части перед :)

Puck 11.12.2020 16:08

@Puck Да, аргументы являются свойствами построителя. Я добавил немного больше иллюстраций, otherService обрабатывается как ресурс данных DAO или spring (просто для примера), а метод get() выполняет некоторое преобразование результатов, которое часто требуется в службе. Надеюсь, это поможет. Вам, вероятно, придется подумать о проверке аргументов перед делегированием взаимодействующим компонентам.

stridecolossus 11.12.2020 16:23

Большое спасибо, так и будет. Я отметил ваш ответ как принятый.

Puck 11.12.2020 16:24

Другие вопросы по теме