Определение списка Generi c - PullRequest
1 голос
/ 15 марта 2020

Я довольно новичок в Generics и буду очень признателен за помощь. У меня есть метод,

1 public static List<classA> convertA(List<List<Object>> dataframe) throws Exception {
2       List<classA> objA = new ArrayList<classA>();
3       for (List<Object> objs : dataframe) {
4           if (objs != null) {
5               classA a = new classA();

6               //generic logic to set value from objs to object `a` irrespective of type of `a`. 

7               objA.add(a);
8           }
9       }

10      return objA;
11  }

Метод в основном присваивает значения List<List<Object>> dataframe списку classA.

У меня также есть другой метод convertB который имеет тот же лог c и аргумент convertA, за исключением того, что он хранит значения данных в списке classB(List<classB>), например,

21 public static List<classB> convertB(List<List<Object>> dataframe) throws Exception {
22      List<classB> objA = new ArrayList<classB>();
23      for (List<Object> objs : dataframe) {
24          if (objs != null) {
25              classB b = new classB();

26              //generic logic to set value from objs to object `b` irrespective of type of `b`. 

27              objA.add(b);
28          }
29      }

30      return objA;
31  }

Так что я пытаюсь объединить 2 метода в один, чтобы написать общий метод generi c с возвращаемым типом List<T> и аргументами, включая тип T (который может быть classA, classB, ..), что-то вроде этого,

public static List<T> convertGeneric(List<List<Object>> dataframe, T t) 

Но я не уверен, как написать строки 2,5,7 в общем c порядке.

Так может ли кто-нибудь указать мне правильное направление?

Обратите внимание:

Оба метода convertA и convertB не зависят от друг друга и используются для обработки 2 отдельных сцен ios. Между этими двумя понятиями нет никакой связи, за исключением того факта, что оба имеют один и тот же лог c для преобразования List<Object> objs в соответствующий объект, а именно a(classA) или b(classB).

Вместо того, чтобы поддерживать 2 отдельных метода как convertA() и convertB(), я просто пытаюсь превратить его в один, который я могу вызвать, передавая аргументы типа

List<ClassA> ls = convertGeneric(dataframe, ClassA.class); вместо convertA() и

List<ClassB> ls1 = convertGeneric(dataframe, ClassB.class); вместо convertB().

Ответы [ 2 ]

1 голос
/ 15 марта 2020

Решение с использованием метода Generi c

Определите ваш метод generi c как

public static <T> List<T> convertGeneric(List<List<Object>> dataframe, Function<Object, T> converter)

, т.е. первый аргумент - это ваша коллекция объектов, а в качестве второго аргумента Вы предоставляете функцию преобразования из Object в целевой класс. Метод возвращает List<T>. (Обратите внимание на <T> после static, который требуется для объявления метода generi c.

Реализация метода может быть

public static <T> List<T> convertGeneric(List<List<Object>> dataframe, Function<Object, T> converter) {

  List<T> result = new ArrayList<>();

  for (List<Object> objects : dataframe) {
    for (Object object : objects) {
      T t = converter.apply(object);
      result.add(t);
    }
  }

  return result;
}

или другой, использующей потоки:

public static <T> List<T> convertGeneric(List<List<Object>> dataframe, Function<Object, T> converter) {

  return dataframe.stream()
          .flatMap(Collection::stream)    // get the objects from the inner list
          .map(converter)                 // convert object to T
          .collect(Collectors.toList());  // put everything in a new list
}

Функция преобразования может быть реализована как лямбда, например,

Function<Object, Foo> fooLambda = object -> {
  Foo foo = new Foo();
  // logic for mapping obj to foo
  return foo;
};

И преобразование List<List<Object>> в List<Foo> становится:

List<Foo> fooList = GenericMethodConverter.convertGeneric(dataFrame, fooLambda);

Я думаю, что причина, по которой вы боролись с этой проблемой, заключается в том, что вы пытались сделать все (абстрактное и конкретное) в методе generi c. Вы знали, что метод generi c требует дополнительной информации, что конкретная реализация для использования (в вашей версии путем передачи в качестве второго аргумента целевого типа для преобразования). В приведенном выше решении для метода generi c требуется функция преобразования Function<Object,T>, то есть функция, которая отображает объект на тип цели T. Метод generi c применяет эту функцию ко всем объектам и помещает результаты в возвращенный список. Конкретная реализация для отображения object в Foo предоставляется в виде лямбда-выражения, таким образом преобразуя родовые c T в Foo. Другие функции преобразования могут быть добавлены по мере необходимости.

Другой подход

Это решение, использующее объектные ориентации / классы вместо методов stati c:

Определение абстрактного базового класса GenericConverter, который содержит итерацию для над списком и объявляет абстрактный метод преобразования Object в целевой тип:

public abstract class GenericConverter<T> {

  public List<T> convertGenerically(List<List<Object>> dataFrame) {

    List<T> tList = new ArrayList<>();

    for (List<Object> objectList : dataFrame) {
      for (Object obj : objectList) {
         T t = convert(obj);
         tList.add(t);
       }
    }
    return tList;
  }

  protected abstract T convert(Object obj);
}

Добавьте реализацию для каждого целевого класса, например, для преобразования Object в Foo:

public class FooConverter extends GenericConverter<Foo> {

    @Override
    protected Foo convert(Object obj) {
        Foo foo = new Foo();

        // logic for mapping obj to foo

        return foo;
    }
}

А затем преобразовать Objects, вызвав метод реализации класса:

List<Foo> foos = fooConverter.convertGenerically(dataFrame);
0 голосов
/ 15 марта 2020

Если я вас правильно понял, вам нужно создать интерфейс и реализовать его в ваших classA и classB. Затем используйте этот интерфейс в качестве заполнителя c. Пример:

public class ClassA implements  Interface {
}

public class ClassB implements  Interface {
}



 ArrayList<Interface> objA = new ArrayList<>();
        objA.add(new ClassA());
        objA.add(new ClassB());
        for (Interface obj : objA) {
            //logic
            }
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...