Общий интерфейс против интерфейса для каждого типа

Есть два класса X, Y, которые реализуют базовый интерфейс. Существует интерфейс, который занимается обработкой объектов каждого типа.

interface Base {
}
class X implements Base {
}
class Y implements Base {
}

interface XProcessor {
    void process(X object);
}
interface YProcessor {
    void process(Y object);
}

Но недостатком такого подхода является то, что я должен выставлять один интерфейс для каждого типа объекта (X, y..), и если таких объектов много, я бы в конечном итоге выставил слишком много интерфейсов. Я думал, что справлюсь с этим, предоставив только один интерфейс, который занимается обработкой объектов типа Base.

interface Processor<E extends Base> {
  void process(E object);
}

Разработчик пишет свою реализацию для обработки объектов типа X как

class XProcessor implements Processor<X> {
    void process(X object) {
        //do something
    }
}

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

void process(Processor p) {
    p.process(??);
}

Есть ли лучший способ справиться с этой проблемой?


person themanwhosoldtheworld    schedule 08.10.2013    source источник
comment
Возникает вопрос: зачем вам действительно нужно знать класс во время выполнения? Если вы не можете обобщить процесс, то работайте с каждым классом.   -  person Luiggi Mendoza    schedule 08.10.2013
comment
Можно ли это обработать с помощью Factory для разных Processor?   -  person tredontho    schedule 08.10.2013


Ответы (3)


как предложил @tredontho, можно использовать фабрику ProcessorFactory, как показано ниже, чтобы получить соответствующий экземпляр, а затем вызвать метод процесса

public class ProcessTest {

    <T extends Base> void processBase(T base) {
        ProcessorFactory.getProcessor(base).process(base);
    }

}


interface Base{
}
class X implements Base{
}
class Y implements Base{
}

interface Processor<E extends Base>{
    void process(E object);
}

interface XProcessor extends Processor<X> {

}
interface YProcessor extends Processor<Y> {

}

class ProcessorFactory {

    @SuppressWarnings("unchecked")
    static <T extends Base> Processor<T> getProcessor(T base) {
        if (base instanceof X) {
            return (Processor<T>) new XProcessorImpl();
        }
        return null;
    }

}

class XProcessorImpl implements XProcessor {

    @Override
    public void process(X object) {
        // TODO Auto-generated method stub

    }

}
person Dev Blanked    schedule 08.10.2013
comment
Это выглядит чистым. Однако в моем случае интерфейс «Процессор» будет доступен пользователю, и он его реализует. Во время выполнения мы получим все классы, которые реализуют интерфейс «Процессор» и вызовут их метод «процесс». Итак, еще раз, если у нас нет интерфейса для каждого типа объекта, такого как «XProcessor» для объектов типа «X», невозможно выяснить, какой тип объекта передать методу процесса во время выполнения. Поэтому в моем случае я думаю, что одного универсального интерфейса будет недостаточно, и я должен предоставить интерфейс для каждого типа объекта. - person themanwhosoldtheworld; 09.10.2013
comment
@Kalyan, вы могли бы ввести 'Class‹E› getSupportedClass();' к интерфейсу процессора и заставить разработчиков интерфейса предоставлять поддерживаемый класс. Используя это, вы можете выяснить, какую реализацию процессора использовать для данного базового экземпляра. - person Dev Blanked; 09.10.2013
comment
хм, это хорошо, хотя выглядит не очень элегантно. - person themanwhosoldtheworld; 09.10.2013

Это не имеет ничего общего со временем выполнения. Вы уже удалили тип во время во время компиляции, если написали что-то вроде

void process(Processor p){
  p.process(??);
}

Если ваш интерфейс Processor является универсальным, вам больше не следует использовать необработанный тип:

<E extends Base> void process(Processor<E> p){
  p.process(…instance of E…);
}

Например:

<E extends Base> void processAll(Processor<E> p, Collection<? extends E> c){
  for(E item: c) p.process(c);
}
person Holger    schedule 08.10.2013

Должен ли метод process() должен иметь параметр?

Может быть, вы пойдете следующим путем?

Каждый отдельный класс реализует общий интерфейс processor, который включает в себя заглушку для метода void process(), таким образом создавая свое собственное действие. Затем вы можете upcast свои объекты использовать в интерфейсе (при необходимости поместить их в какую-то коллекцию).

У вас может быть что-то вроде:

List<Processor> p = new ArrayList<>();
p.add(new Xprocessor);
p.add(new Yprocessor);

for each(Processor pr: p) {
   pr.Processor();
}

а полиморфизм позаботится обо всем остальном.

В таком случае вам даже не понадобятся дженерики.

person PM 77-1    schedule 08.10.2013
comment
Это шаблон посетителя. - person Riga; 11.10.2013