Я пытаюсь реорганизовать некоторый код, чтобы уменьшить дублирование кода. В настоящее время у меня есть служба, которая принимает собственный класс 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, а также на решениях по проектированию кодовой базы)
Вот именно, у них вообще нет общих полей, единственное, что у них общего, это то, что они просто возвращаются из метода getResponse. Аналогично и для класса Response, и это не может измениться по причинам, в которые я не могу вдаваться.
Можете ли вы передать TypeReference<T>
в метод getResponse()
и вернуть T
?
Подойдет ли вам что-то подобное?
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, но не переопределяет его.
это правильно, переопределение не работает с универсальными типами - это означает замену, а НЕ переопределение. Вам следует использовать только этот метод для всех своих сервисов.
Ах, я вижу, спасибо! Я еще немного почитаю о дженериках и упс :)
Разве это не TypeReference
просто указывало бы на Object
все время?
Дженерики для TypeReference
здесь не делают того, что вы хотите.
ребята, вы правы, я обновил ответ
У меня недостаточно информации, чтобы ответить, в чем разница между полезными нагрузками и ответами типов A,B,C? Пока у нас не будет определений всех этих классов, невозможно будет ответить.