1

是否可以在 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() 方法中。这样我就可以确定插入的工具类型是合法工具。

客户端代码应如下所示:

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(); 返回 p;

提前感谢您帮助我。

4

1 回答 1

7

有几件事:

  1. 你的工厂几乎肯定应该使用一个来实例化,而不是一个 Tool对象。让某人创建 aParser并将其传递给您的方法以获取Parsera 有点鸡和蛋。
  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()

顺便说一句,这种静态硬编码切换通常不是很好。在我看来,将类与构造函数的关系放在 a 中Map并动态查找构造过程会更好。甚至可能将值存储为 aCallable<? extends Tool>并添加一个受保护的方法,允许其他类注册映射。

这并不是说您当前的版本不起作用,只是它不能很好地扩展,而且现在我认为证明拥有一个单独的工厂而不是调用者简单地调用toolClass.newInstance()自己并没有多大作用。

于 2010-11-11T11:15:21.933 回答