В моей реализации я хочу иметь другой возвращаемый тип метода

#java

#java

Вопрос:

У меня следующая проблема. У меня есть интерфейс:

 public interface Parser {
    public Map<String, List<String>> parse() throws IOException;
}
  

У меня есть две реализации:

 public class RacerInfoParser implements Parser{

    private final Path path;

public RacerInfoParser(Path path) {
    this.path = path;   
}

@Override
public Map <String, List<String>> parse() throws IOException {
    try (Stream<String>lines = Files.lines(path)){
        
        Map <Object, Object> map = lines.collect(Collectors.toMap(
                string -> string.substring(0,3),
                string -> Arrays.asList(string.substring(4).split("_"))));
        
        Map<String, List<String>> result = new HashMap<>((Map) map);
        return resu<
        }
    }
}
  

и

 public class TimeParser implements Parser {

    private final Path path;

public TimeParser(Path path) {
    this.path = path;   
}


@Override
public Map <String, List<String>> parse() throws IOException {
    try (Stream<String>lines = Files.lines(path)){
        
        Map <Object, Object> map = lines.collect(Collectors.toMap(
                string -> string.substring(0,3),
                string -> Arrays.asList(string.substring(3).split("_"))));
        Map<String, List<String>> result = new HashMap<>((Map) map);
    return resu<
        }
    }
}
  

Что я хочу сделать, так это изменить код и возвращаемый тип анализатора времени, чтобы он возвращал результат типа Map<String, List <LocalTime> . Я читал, что для того, чтобы иметь другой тип, мне нужно иметь подкласс родительского типа, но я не понимаю, как это сделать в моем случае.

PS Я знаю, что Map<String, List<String>> result = new HashMap<>((Map) map); это плохой код, но я пока не знаю, как правильно преобразовать Map<Object, Object в Map<String, List<String>> . Если у вас есть какие-либо предложения, я буду рад их выслушать :).

PSS Я использую эти две реализации, потому что я верю, что они делают одно и то же: анализируют текст из файлов журнала и txt:

     public class RacerBuilder {
        public List<Racer> buildRacers () throws URISyntaxException, IOException {
    
            Parser racerInfoParser = new RacerInfoParser(Paths.get(getClass().getClassLoader()
                      .getResource("abbreviations.txt").toURI()));
            Parser startTimeParser = new TimeParser(Paths.get(getClass().getClassLoader()
                      .getResource("start.log").toURI()));
            Parser endTimeParser = new TimeParser(Paths.get(getClass().getClassLoader()
                      .getResource("end.log").toURI()));
            
            Map<String, List<String>> racerInfoMap = racerInfoParser.parse();
            Map<String, List<String>> startTimeMap = startTimeParser.parse();
            Map<String, List<String>> endTimeMap = endTimeParser.parse();
    
            return racerInfoMap.keySet().stream()
                    .map(i -> new Racer (i,
                            racerInfoMap.get(i).get(0),
                            racerInfoMap.get(i).get(1),
                            startTimeMap.get(i).get(1),
                            endTimeMap.get(i).get(1),
                            endTimeMap.get(i).get(0)))
                    .collect(Collectors.toList());  
           }
}
  

Класс Racer теперь имеет несколько полей, все они являются строками. Я хочу, чтобы в нем было 2 поля типа LocalTime.

Комментарии:

1. Сделайте ваш анализатор универсальным интерфейсом: public interface Parser<T> { ... } с помощью метода Map<String, List<T>> parse() .

2. Также. Map <String, List<String>> выглядит сложным для возвращаемого типа. Возможно, вам не хватает понимания домена. Сам Map <String, List<T>> по себе может быть новым классом.

3. Не могли бы вы, пожалуйста, подумать / добавить в код вопроса, который показывает, как вы планируете использовать тот факт, что эти два класса реализуют один и тот же интерфейс Parser . В чем преимущество членства в одной иерархии при разных типах возвращаемых данных?

4. @MarkBramnik, я немного отредактировал свой вопрос, теперь я надеюсь, что это немного понятнее.

5. @IceTeaGreen что вы подразумеваете под последней строкой, и давайте закроем вопрос, если вы удовлетворены ответом, который вы приняли.

Ответ №1:

Чтобы принять либо :

 Map<String, List<String>>
  

или

 Map<String, List<LocalTime>>
  

В этом случае вы можете использовать generic, все, что вам нужно, это использовать :

 <T> Map<String, List<T>> parse() throws IOException;
                     ^
  

Также ваш код может быть :

 return lines.collect(Collectors.toMap(
        string -> string.substring(0, 3),
        string -> Arrays.asList(string.substring(4).split("_"))));
  

Или, если вам нужен список LocalTime, вы можете проанализировать свою строку и собрать ее следующим образом:

 return lines.collect(Collectors.toMap(
        string -> string.substring(0, 3),
        string -> Arrays.stream(string.substring(4).split("_"))
        .map(LocalTime::parse) // or you can use a Date time formatter
        .collect(Collectors.toList())
  

Вам не нужно использовать это решение.

Ответ №2:

Я бы обернул Map<String, List<String>> в новый класс с помощью getter, назовем его MapAsString . Сделайте его частью иерархии классов, чтобы у вас было class MapAsString extends DataMap . Затем создайте новый класс, который является подклассом DataMap called , возможно MapAsLocalTime , where MapAsLocalTime extends DataMap .

Бонусные баллы: сделайте свой родительский class DataMap абстрактный и предоставьте один абстрактный метод, который вы должны реализовать. который использует дженерики для возврата a List<String, T> . У вас может быть конструктор, который принимает T (общий тип), который определяет, какой тип T будет во время построения. Если это кажется слишком сложным, возможно, просто верните что-нибудь, используя подстановочный ? знак… итак, возвращает getter List<String, ?> — здесь ? может быть объект любого типа

Ответ №3:

Вы можете использовать generics T. Например, таким образом

 interface Parser<T> {
    public Map<String, List<T>> parse() throws IOException;
}

class RacerInfoParser implements Parser<String>{

    private final Path path;

    public RacerInfoParser(Path path) {
        this.path = path;   
    }
    
    @Override
    public Map <String, List<String>> parse() throws IOException {
        try (Stream<String>lines = Files.lines(path)){
            
            Map <String,  List<String>> map = lines.collect(Collectors.toMap(
                    string -> string.substring(0,3),
                    string -> Arrays.asList(string.substring(4).split("_"))));
            return map;
            }
        }
    }

class TimeParser implements Parser<LocalTime> {

    private final Path path;

public TimeParser(Path path) {
    this.path = path;   
}


@Override
public Map <String, List<LocalTime>> parse() throws IOException {
    try (Stream<String>lines = Files.lines(path)){
        
        Map<String, List<LocalTime>> result = lines.collect(Collectors.toMap(
                string -> string.substring(0,3),
                string -> Arrays.stream(string.substring(4).split("_"))
                .map(LocalTime::parse)
                .collect(Collectors.toList())
                ));
            return resu<
        }
    }
}