#java #spring #list #generics
#java #spring #Список #общие
Вопрос:
Я разрабатываю веб-сайт для своей компании, и я использую Spring в качестве своего бэкэнда. Сейчас возникла ситуация, когда мне нужно использовать один из моих Utils-методов дважды, но для разных DAO.
Чтобы избежать дублирования кода, мне было интересно, как я могу использовать Java Generics, чтобы сделать этот метод пригодным для обоих случаев. Метод просто считает одно из полей, которое является общим для обоих DAO.
Метод Util :
SeverityCount calculateSeveritiesCount(List<?> events){
if(null == events){
return new SeverityCount();
}
if(events.get(1) instanceof EventDAO){
events = (List<EventDAO>)events;
}
else if (events.get(1) instanceof EventsByAreaDAO) {
events = (List<EventsByAreaDAO>)events;
}
Map<String, Long> severityCountMap = events.stream().collect(
Collectors.groupingBy(
EventDAO::getSeverity, //It should be EventDAO or EventsByAreaDAO. both has severity field.
Collectors.counting())
);
return mapper.convertValue(severityCountMap, SeverityCount.class);
}
Event DAO:
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "events")
public class EventDAO {
@Id @Column(name = "uid")
private String uID;
private String date;
private String severity;
}
Область DAO:
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "events")
public class EventsByRegionDAO {
@Id @Column(name = "uid")
private String uID;
private String date;
private String type;
private String severity;
private String area;
private String server;
}
Вот как я вызываю его из сервиса:
SeverityCount severitiesCount = Utils.calculateSeveritiesCount(eventsList); //EventsList could be list of EventDAO or EventsByAreaDAO
Комментарии:
1. можете ли вы создать для них общий интерфейс?
2. Код, который я показал, не работает из-за этой строки: EventDao::getSeverity, в методе utils. Мне нужно определить тип DAO на основе типа списка, который я получил
3. верно, я удалил этот комментарий… прочитайте другой еще раз, пожалуйста, и дайте нам знать
Ответ №1:
Вы можете изменить метод на
SeverityCount calculateSeveritiesCount(List<? extends SeverityCalculable> events)
где SeverityCalculable
interface SeverityCalculable {
String getSeverity(); // implemente getter in all subclasses
}
Пусть все ваши соответствующие классы реализуют этот интерфейс.
public class EventDAO implements SeverityCalculable {
// ...
@Override
public String getSeverity() {
return this.severity;
}
}
Теперь в вашем методе удалите приведения, и это должно стать чем-то вроде этого:
SeverityCount calculateSeveritiesCount(List<? extends SeverityCalculable> events) {
if(null == events){
return new SeverityCount();
}
Map<String, Long> severityCountMap = events.stream().collect(
Collectors.groupingBy(
SeverityCalculable::getSeverity,
Collectors.counting()
)
);
return mapper.convertValue(severityCountMap, SeverityCount.class);
}
Ответ №2:
Поскольку оба DAO имеют severity
свойство, они потенциально могли бы реализовать общий интерфейс, скажем SeverityAware
:
public interface SeverityAware {
public String getSeverity();
}
public class EventsByRegionDAO implements SeverityAware { .. }
public class EventDAO implements SeverityAware { .. }
Кроме того, ваш метод теперь может принимать подтипы этого интерфейса:
SeverityCount calculateSeveritiesCount(List<? extends SeverityAware> events){
if (null == events){
return new SeverityCount();
}
Map<String, Long> severityCountMap = events.stream().collect(Collectors.groupingBy(
SeverityAware::getSeverity,Collectors.counting())
);
return mapper.convertValue(severityCountMap, SeverityCount.class);
}
Комментарии:
1. Я признаю,
SeverityAware
звучит лучше, чемSeverityCalculable
2. @MarkoPacak Как насчет «общего» именования [SomeThingItDoes] [able] ->
Severityable
😉