java参数化通用静态工厂

时间:2010-11-11 11:10:16

标签: java generics design-patterns factory factory-method

在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;

先谢谢你的帮助。

1 个答案:

答案 0 :(得分:6)

有几件事:

  1. 您的工厂几乎肯定会使用来实例化,而不是工具对象。让某人创建Parser以传递给您的方法以获得Parser有点鸡蛋和鸡蛋。
  2. 我不知道你是否允许使用通配符方法的通用参数;我认为不会,因为这将是荒谬和毫无意义的。在参数化方法时,需要为泛型参数指定一个名称,以便稍后可以引用它。
  3. 将这些放在一起,您的工厂方法可能看起来更像这样:

    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}}他们自己。