Как переопределить универсальный метод в подклассе Java

Я пытаюсь реорганизовать некоторый код, чтобы уменьшить дублирование кода. В настоящее время у меня есть служба, которая принимает собственный класс Payload и возвращает собственный класс Response. И в настоящее время это делает не один сервисный класс, а около 5 или 6. Таким образом, это приводит к МНОГО дублирования кода, хотя тело методов буквально одинаковое, отличается только тип возвращаемого значения.

Например:

public class ServiceA {
    ResponseA getResponse(PayloadA){...}
}
public class ServiceB {
    ResponseB getResponse(PayloadB){...}
}
public class ServiceC {
    ResponseC getResponse(PayloadC){...}
}

Там, где тела метода буквально дословно одинаковы, но поскольку это почтовый запрос с использованием WebClient, где методы заканчиваются на ObjectMapper mapper = new ObjectMapper(); return mapper.readValue(response, new TypeReference<>() {});, мы просто копируем метод снова и снова.

Я попытался реализовать абстрактный суперкласс под названием RestService и иметь два пустых интерфейса под названием RestResponse и RestPayload, которые каждый сервис может реализовать самостоятельно, но тогда как мне заставить класс обслуживания возвращать свой собственный тип Response, а не тип RestResponse, который является просто пустой интерфейс?


РЕДАКТИРОВАТЬ - ОБНОВИТЬ: Итак, в некоторой связи я решил свою проблему, выполнив следующие действия:

public abstract class ParentService<R extends IResponse, P extends IPayload>{
  public abstract R getPayload(P);
}

public class ServiceA extends ParentService<ResponseA, PayloadA> {
  @Override
  public ResponseA getPayload(PayloadA){
    /***/
    ObjectMapper mapper = new ObjectMapper();     
    return mapper.readValue(response, new TypeReference<>() {});
  }
}

Где каждая дополнительная услуга наследуется аналогичным образом. И каждый ответ и полезная нагрузка реализуют модели интерфейса IResponse и IPayload соответственно.

Спасибо вам за ваши предложения!

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

У меня недостаточно информации, чтобы ответить, в чем разница между полезными нагрузками и ответами типов A,B,C? Пока у нас не будет определений всех этих классов, невозможно будет ответить.

J Asgarov 10.07.2024 17:14

Вот именно, у них вообще нет общих полей, единственное, что у них общего, это то, что они просто возвращаются из метода getResponse. Аналогично и для класса Response, и это не может измениться по причинам, в которые я не могу вдаваться.

iyers16 10.07.2024 17:38

Можете ли вы передать TypeReference<T> в метод getResponse() и вернуть T?

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

Ответы 1

Ответ принят как подходящий

Подойдет ли вам что-то подобное?

  • T вернет тип, который хочет вызывающий метод.
  • Полезная нагрузка может быть любого типа
public class GeneralService {
    public <T> T getResponse(Object payload, Class<T> clazz){
        // do sth with payload
        return mapper.readValue(response, clazz);
    }
}

Если вы также хотите иметь возможность десериализовать коллекции, вы можете использовать TypeReference вместо Class:

public class GeneralService {
    public <T> T getResponse(Object payload, TypeReference<T> type){
        // do sth with payload
        return mapper.readValue(response, type);
    }
}

а затем вызовите его с типом, например, для списка строк:

generalService.getResponse(payload, new TypeReference<List<String>>(){})

Итак, я попробовал этот метод, но когда я переопределяю его в определенном классе ServiceXYZ и пытаюсь использовать ResponseXYZ в качестве возвращаемого типа, он говорит: Конфликт имен: метод getResponse(Set<String>) типа ServiceXYZ имеет то же стирание, что и getResponse. (Set<String>) типа RestService, но не переопределяет его.

iyers16 10.07.2024 17:52

это правильно, переопределение не работает с универсальными типами - это означает замену, а НЕ переопределение. Вам следует использовать только этот метод для всех своих сервисов.

J Asgarov 10.07.2024 17:53

Ах, я вижу, спасибо! Я еще немного почитаю о дженериках и упс :)

iyers16 10.07.2024 17:57

Разве это не TypeReference просто указывало бы на Object все время?

M. Prokhorov 10.07.2024 18:30

Дженерики для TypeReference здесь не делают того, что вы хотите.

Louis Wasserman 10.07.2024 18:38

ребята, вы правы, я обновил ответ

J Asgarov 10.07.2024 18:41

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