Java параметризованный универсальный статический завод

Возможно ли в Java создать статический фабричный метод / класс, который использует интерфейс в качестве параметризованного типа, и вернуть реализующий класс этого данного интерфейса?

Хотя мои знания в области дженериков ограничены, я хочу сделать следующее:

// define a base interface:
public interface Tool {
    // nothing here, just the interface.
}

// define a parser tool:
public interface Parser extends Tool {
    public ParseObject parse(InputStream is); 
}

// define a converter tool:
public interface Converter extends Tool {
    public ConvertObject convert(InputStream is, OutputStream os);
}

// define a factory class
public class ToolFactory {
    public static <? extends Tool> getInstance(<? extends Tool> tool) {
       // what I want this method to return is:
       // - ParserImpl class, or
       // - ConverterImpl class
       // according to the specified interface.
       if (tool instanceof Parser) {
          return new ParserImpl();
       }
       if (tool instanceof Converter) {
          return new ConverterImpl();
       }
    }
}

Я хочу ограничить код клиента, чтобы он вставлял только интерфейсный тип в метод getInstance(), который расширяется из интерфейса Tool, который я указал. Таким образом, я точно знаю, что вставленный тип инструмента является законным инструментом.

Код клиента должен выглядеть так:

public class App {
   public void main(String[] args) {

      Parser parser = null;
      Converter converter = null;

      // ask for a parser implementation (without knowing the implementing class)
      parser = ToolFactory.getInstance(parser);

      // ask for a converter implementation
      converter = ToolFactory.getInstance(converter);

      parser.parse(...);
      converter.convert(... , ...);
   }
}

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

Тип возвращаемого значения метода getInstance совпадает с входящим параметром, поэтому при передаче интерфейса Parser он также возвращает Parser p = new ParserImpl(); возврат р;

Заранее спасибо за помощь.

1 ответ

Решение

Пара вещей:

  1. Ваша фабрика почти наверняка должна использовать экземпляр класса, а не объект Tool. Когда кто-то создает Parser перейти в ваш метод, чтобы получить Parser немного курицы с яйцом.
  2. Я не знаю, разрешено ли вам иметь общие параметры для методов, которые являются подстановочными знаками; Я полагаю, нет, так как это было бы бессмысленным и бессмысленным. Когда вы параметризируете метод, вам нужно дать универсальному параметру имя, чтобы вы могли обратиться к нему позже.

Собрав их вместе, ваш фабричный метод может выглядеть примерно так:

public static <T extends Tool> T getInstance(Class<T> toolClass) {
   if (Parser.class.isAssignableFrom(toolClass) {
      return new ParserImpl();
   }
   else if (Converter.class.isAssignableFrom(toolClass) {
      return new ConverterImpl();
   }

   // You'll always need to have a catch-all case else the compiler will complain
   throw new IllegalArgumentException("Unknown class: " + toolClass.getName());
}

Если вы хотите ограничить тип toolClass чтобы быть интерфейсом, вы не можете сделать это во время компиляции, но вы, конечно, можете ввести проверку во время выполнения toolClass.isInterface(),

Кстати, это статическое переключение с жестким кодом не очень хорошо в целом. На мой взгляд, было бы лучше поместить отношение класс-конструктор в Map и посмотреть на процесс строительства динамически. Может быть, даже сохранить значение как Callable<? extends Tool> и добавьте защищенный метод, позволяющий другим классам регистрировать сопоставления.

Это не значит, что ваша текущая версия не работает, просто она не очень хорошо масштабируется, и сейчас я не думаю, что она делает много для оправдания наличия отдельной фабрики, а не просто вызова вызывающей стороны toolClass.newInstance() самих себя.

Другие вопросы по тегам