在Java中是否可以创建一个静态工厂方法/类,它使用接口作为参数化类型并返回给定接口的实现类?
虽然我对Generics的了解有限,但这就是我想做的事情:
// 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();
}
}
}
我想限制客户端代码只将接口'type'插入到我指定的Tool接口扩展的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(); return p;
先谢谢你的帮助。
答案 0 :(得分:6)
有几件事:
Parser
以传递给您的方法以获得Parser
有点鸡蛋和鸡蛋。将这些放在一起,您的工厂方法可能看起来更像这样:
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>
并添加一个受保护的方法,允许其他类注册映射。
这并不是说你当前的版本不起作用,只是它不能很好地扩展,而且现在我认为它没有做太多证明有一个单独的工厂而不是调用者只是调用{ {1}}他们自己。