Возврат данных от void-посетителя без изменения абстрактного посетителя - PullRequest
0 голосов
/ 20 июня 2019

Я использую Java-фреймворк, который предоставляет какой-то шаблон посетителей для обработки элементов. Существует абстрактный суперкласс AbstractProcessor<T> (который я не могу изменить), который предоставляет метод public abstract void process(T visitedElement).

Затем я определил несколько конкретных реализаций таких процессоров и создал их экземпляр с помощью Factory Pattern, чтобы затем использовать их через общий супертип. Теперь, как я могу получить любую информацию оттуда? Я, очевидно, не могу просто что-то вернуть, поскольку абстрактный метод процесса имеет тип void.

Пока я думал только о поле данных, которое я мог бы добавить к конкретной реализации (поскольку я не могу изменить абстрактный суперкласс), поэтому сделать что-то вроде этого:

public class MyProcessor extends AbstractProcessor<SomeType> {
public String data;

  @Override
  public void process(SomeType t) {
  [do stuff...]
  this.data = "some important info";
  }
}

Но чтобы получить эти данные - скажем, список их общих супертипов, которые не имеют поля данных - мне нужно было бы сделать некрасивую проверку типов и приведение типа:

List<AbstractProcessor> list = getProcessors();
list.forEach(p -> {
  someType.processWith(p); //someType accepts AbstractProcessor's and then runs their process-method
  if(p instanceOf MyProcessor) 
    System.out.println( ((MyProcessor)p).data );
  }
});

Есть ли какой-либо другой способ получения данных какого-либо типа, которые рассчитываются по методу process таким образом?

Ответы [ 3 ]

0 голосов
/ 20 июня 2019

Я думаю, что у вас есть неразрешимая проблема.Я так понимаю, вы говорите:

  • Вы написали несколько AbstractProcessor подклассов.
  • Все они делают разные вещи и дают разные результаты.
  • Вы хотитеотноситься к ним все однородно, как к экземплярам AbstractProcessor.

Но вы не можете относиться к ним как к экземплярам одного и того же класса AbstractProcessor, если все они дают разные результаты.Вы должны знать, какой тип процессора у вас есть, чтобы интерпретировать результаты.

У вас есть два варианта.Первый вариант - унифицировать результаты.Например, у вас может быть интерфейс с именем ResultHandler, например:

interface ResultHandler {
   void handleSumResult(int result);
   void handleConcatResult(String result);
   void handleSomeOtherProcessorResult(Whatever result);
}

Передача экземпляра ResultHandler (либо в процессе построения, либо в отдельном методе handleResult), затем (в каждомпроцессор) вызвать метод ResultHandler, соответствующий этому типу процессора.Если у вас есть несколько разных процессоров, которые каким-то образом генерируют суммы, по крайней мере, все они могут вызывать один и тот же handleSumResult API, и вам не нужно никуда делать instanceof.

Другая стратегия состоит в том, чтобы простооткажитесь от вашей попытки одинаково относиться ко всем процессорам.Я думаю, что это может быть лучшим вариантом.Ваш код, очевидно, знает, какой процессор ему нужно использовать, поэтому просто создайте его экземпляр, используйте его и соберите результаты из любого API, который вы определили.Если есть какая-то причина, по которой вам нужно обрабатывать процессоры однородно (например, класс процессора указан пользователем, может быть, в файле конфигурации), то переместите эту абстракцию на один уровень вверх и вместо этого попросите пользователя указать класс, которому принадлежит весьПроцесс обработки данных и сбора результатов.Вместо указания MyProcessor, использование указывает MySomethingElse, а затем MySomethingElse создает экземпляр MyProcessor и обрабатывает результаты.

0 голосов
/ 20 июня 2019

Вы можете заставить процессоры «выталкивать» данные, например, в хеш-карту, которая передается или доступна глобально.

public class MyProcessor extends AbstractProcessor<SomeType> {
  public Map<Object, String> data;

  @Override
  public void process(SomeType t) {
  [do stuff...]
  this.data.put(this, "some important info");
  }
}

Таким образом, клиент может получить информацию, какой абстрактный процессор добавил, какую информацию, все, что ему нужно, - это доступ к карте.

0 голосов
/ 20 июня 2019

Я бы не использовал здесь поле. Вместо этого: определите подходящий интерфейс, например ResultProcessor , который имеет метод T getResult () . И затем все эти подклассы, которые должны произвести результат, реализуют этот интерфейс.

Конечно, вы все равно должны использовать приведение, но, по крайней мере, вы можете использовать универсальный T для гибкости, и ваши клиенты могут вызывать метод вместо прямого доступа к полю.

...