Java параметризованный универсальный статический завод - PullRequest
1 голос
/ 11 ноября 2010

Возможно ли в 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 (); return p;

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

1 Ответ

6 голосов
/ 11 ноября 2010

Пара вещей:

  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() сами.

...