Java параметризованный общий статический factory

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

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

// 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(), который простирается от указанного интерфейса инструмента. Таким образом, я точно знаю, что введенный тип инструмента является законным инструментом.

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

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(... , ...);
   }
}

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

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

Заранее благодарим за помощь.

Ответ 1

Несколько вещей:

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

Объединяя их, ваш метод factory может выглядеть примерно так:

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> и добавьте защищенный метод, позволяющий другим классам регистрировать сопоставления.

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