Я знаю, что есть много подобных вопросов, но мне не удалось найти красивое и чистое решение, если это вообще возможно. Я реализую общий интерфейс с подклассами абстрактного типа. Проблема в том, что когда я их вызываю, я должен либо выполнить приведение типа в переключателе / случае, либо привести тип в каждом методе внутри реализаций интерфейса, и я не могу придумать хороший и чистый подход ... Я лучше просто напишу на короткий пример.
// 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;
}
}
Другое решение может заключаться в переключателе / корпусе внутри класса промежуточного программного обеспечения процессора и приведении в нем ObjAbstractType, но мне пришлось бы написать этот переключатель внутри abcMethod и всех остальных или из метода getProcessor, который возвращает как процессор, так и приведенный ObjType ... поэтому я Придется вернуть какой-нибудь dto, содержащий и то, и другое. : /
Есть ли у вас какие-либо идеи / шаблоны, которые могут помочь мне избавиться от предупреждения о вызове RawType без расширения кода дополнительными переключателями / регистрами или приведениями типов? Желаю тебе хорошего дня, и я буду рад любому обсуждению, Дэвид.
Правильно, я обновил пример кода ... это были просто ошибки типа, поскольку я написал упрощенную версию вместо фактического кода ... Gm <=> Obj ... и о расширениях забыли. :)
Я предполагал все это, но всегда лучше прояснить это. Очень хорошее обновление.




Вам нужен способ сохранить сопоставление между классом 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);
}
}
Хороший способ. Особенно мне нравится тот факт, что расширение Processor новой реализацией теперь означает одну строку внутри конструктора. Спасибо.
Хорошо, я наконец-то должен попробовать, и, к сожалению, он не вернет процессор с карты. Я реализовал его точно так же »(ProcessorInterface <ObjAbstractType>) map.get (obj); ' возвращает null. .. буду смотреть на это.
Добро пожаловать :) Насчет вашего второго комментария, это удивительно. Я только что протестировал компиляцию, и она работает.
Нашел, потребовалось вызвать map.get (obj.getClass ()); ... Мне не хватало этой части .getClass ().
@ Дэвид Хорачек Ой, извините, я этого не заметил. Я только что тестировал компиляцию. Вы быстро поймали проблему, хорошо! Я обновился, чтобы быть правильным.
Я не думаю, что есть существенно более элегантный способ обойти некоторую форму логики 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);
Это выглядит интересно (никогда не думал о таком объявлении), но не может разобраться. Поскольку я возвращаю objProcessor, который является типом ProcessorInterface <ObjType>, он по-прежнему выдает ошибку, что ProcessorInterface <T> несовместим с ним. В любом случае я собираюсь заглянуть в это глубже. :) .. ошибка отображается в строке возврата внутри метода getProcessor.
Работает на моей машине;) Кроме того, решение, которое вы отметили как правильное, использует непроверенное приведение и не защищает от неправильной настройки данных: map.put (ObjType.class, new ScriptProcessor ());
@Fritz Duchardt: Считаете ли вы, что серия условных операторов - лучшее решение? По поводу «не защищает от неправильной настройки данных», как вы думаете, условные выражения больше защищают от опечатки? Вы можете написать if (theClass.isAssignableFrom(ObjType.class)) { return scriptProcessor; }, и компилятор все равно компилируется нормально. Наконец, я не понимаю, как ваш метод может компилироваться без приведения в порядок. T - это параметризованный тип, привязанный к методу. Любой объявленный тип ProcessorInterface, который вы возвращаете, должен соответствовать T.
Где нижний регистр в ProcessorInterface <ObjType> objProcessor = new Processor (). GetProcessor (ObjType.class)?
Я сослался на операторы возврата внутри getProcessor().
Тип возврата getProcessor может быть <T extends ObjTypeAbstract>, что позволяет возвращать ScriptProcessor или ObjProcessor в нижнем регистре.
Это то, что я сказал, но в вашем коде нет приведения.
Извините, конечно, я хочу сказать "без пропуска" :)) Естественно, при использовании ограниченных универсальных типов нет необходимости в приведении типов.
В этом коде действительно много ошибок. Вы пропустили некоторые важные вещи, такие как ключевое слово
extendsдля подклассов. Что такоеGmAbstractType, который вы используете, но не декларируете? Пожалуйста, исправьте его, если вы хотите, чтобы ваш вопрос был удобочитаемым и полезным для других.