Вызов универсального интерфейса Java с абстрактным параметром - PullRequest
0 голосов
/ 09 сентября 2018

Я знаю, что есть много похожих вопросов, но мне не повезло найти хорошее и чистое решение, если это вообще возможно. Я реализую универсальный интерфейс с подклассами абстрактного типа. Проблема в том, что когда я их вызываю, я должен либо выполнять приведение типа в switch / case, либо приведение типа в каждом методе внутри реализации интерфейса, и я не могу придумать хороший и чистый подход ... Я лучше просто напишу вниз короткий пример.

// An abstract type with 2 implementations...
public abstract class ObjTypeAbstract {}

public class ObjType extends ObjTypeAbstract {}
public class ScriptType extends ObjTypeAbstract {}

Теперь процессор для обоих типов с интерфейсом

interface ProcessorInterface<T extends ObjTypeAbstract> {
    public void abcMethod(T obj);
}

public class ObjProcessor implements ProcessorInterface<ObjType> {
    public void abcMethod(ObjType obj) {}
}
public class ScriptProcessor implements ProcessorInterface<ScriptType> {
    public void abcMethod(ScriptType obj) {}
}

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

Идея состояла в том, чтобы просто получить нужный процессор с помощью одного переключателя / корпуса:

public class Processor {
    private ProcessorInterface objProcessor = new ObjProcessor();
    private ProcessorInterface scriptProcessor = new ScriptProcessor();

    public methodAbc(ObjAbstractType obj) {
        getProcessor(obj).abcMethod(obj);
    }

    private ProcessorInterface getProcessor(ObjAbstractType obj) {
        if (obj instanceof ObjType) {
            return objectProcessor;
        } else if (obj instanceof ScriptType) {
            return scriptProcessor;
        }

        return nullProcessor;
    }
}

Это то, что я хотел бы иметь, он также заботится о приведении типа objAbstract к фактическому типу для abcMethod, проблема в том, что это приводит к предупреждению RawType, которое не нарушает код, но я бы хотел избавиться от этого.

И вот где я застрял ... потому что, если я приведу процессоры к определенному типу, как это:

private ProcessorInterface<ObjType> objProcessor = new ObjProcessor();
private ProcessorInterface<ScriptType> scriptProcessor = new ScriptProcessor();

Я не смогу вернуть абстрактный метод из метода getProcessor, поэтому мне пришлось бы реализовать эти интерфейсы с ObjAbstractType со всеми его методами и иметь приведение типов во всех методах каждого процессора, например:

public class ScriptProcessor implements ProcessorInterface<ObjAbstractType> {
    public void abcMethod(ObjAbstractType obj) {
        ScriptType scr = (ScriptType) obj;
    }
}

Другое решение могло бы иметь переключатель / регистр внутри класса промежуточного программного обеспечения Processor и приводить в него ObjAbstractType, но мне пришлось бы написать этот переключатель внутри abcMethod и всех остальных, либо из метода getProcessor, который возвращает и Processor, и приведенный ObjType .. так что я должен был бы вернуть некоторые dto, содержащие оба : /

Есть ли у вас какие-либо идеи / шаблоны, которые могут помочь мне избавиться от предупреждения о вызовах RawType, не расширяя код большим количеством приведений типа switch / case или type? Желаю тебе хорошего дня, и я буду рад любой дискуссии, Дэвид.

Ответы [ 2 ]

0 голосов
/ 09 сентября 2018

Я не думаю, что есть более элегантный способ обойти какую-то форму instanceof логики. Тем не менее, нет необходимости в приведении, если вы добавляете некоторые типы к getProcessor.

    public <T extends ObjTypeAbstract> ProcessorInterface<T> getProcessor(Class<T> theClass) {
        if (theClass.isAssignableFrom(ObjType.class)) {
            return objProcessor;
        } else if (theClass.isAssignableFrom(ScriptType.class)) {
            return scriptProcessor;
        }
        return null;
    }

Это можно тогда назвать так:

    ProcessorInterface<ScriptType> scriptProcessor = new Processor().getProcessor(ScriptType.class);
    ProcessorInterface<ObjType> objProcessor = new Processor().getProcessor(ObjType.class);
0 голосов
/ 09 сентября 2018

Вам нужен способ сохранить отображение между классом ObjTypeAbstract и экземпляром ProcessorInterface.
Вы можете использовать Map, который связывает ObjTypeAbstract с (как ключ) с ProcessorInterface с (как значение).
Что касается проблемы с необработанным типом, вы можете использовать ProcessorInterface<? extends ObjTypeAbstract> для объявленной переменной, но вам все равно потребуется выполнить небезопасное приведение к ProcessorInterface<ObjTypeAbstract>, чтобы иметь возможность вызывать ProcessorInterface.abcMethod() с параметром ObjTypeAbstract объявленного типа.
Этот акт неизбежен с вашим реальным дизайном.

Это может дать что-то вроде:

public class Processor {

    private Map<Class<? extends ObjTypeAbstract>, ProcessorInterface<? extends ObjTypeAbstract >> map = new HashMap<>();

    public Processor(){
        map.put(ObjType.class, new ObjProcessor());
        map.put(ScriptType.class, new ScriptProcessor());   
    }
    public void methodAbc(ObjTypeAbstract obj) {
        @SuppressWarnings("unchecked")
        ProcessorInterface<ObjTypeAbstract> processorInterface = (ProcessorInterface<ObjTypeAbstract>) map.get(obj.getClass());
        processorInterface.abcMethod(obj);
    }

}
...