java参数化通用静态工厂

发布于 2024-10-02 06:14:16 字数 1673 浏览 1 评论 0原文

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

我想限制客户端代码仅将接口“类型”插入到从我指定的 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();返回p;

预先感谢您对我的帮助。

Is it possible in Java to create a static factory method/class that uses an interface as the parameterized type and return an implementing class of this given interface?

Although my knowledge of Generics is limited, here is what I want to do:

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

I want to restrict the client code to only insert an interface 'type' into the getInstance() method that extends from the Tool interface I specified. This way I know for sure that the tooltype that is inserted is a legitimate tool.

Client code should look like this:

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

The factory should switch on the type of the interface (careless if it's null or not), defined before it is asked from the factory. I know this is not going to work the way I wrote this, but I hope one of the readers knows what I want to accomplish.

The return type of the getInstance method is the same as the incoming parameter, so when a Parser interface is passed, it also returns a Parser p = new ParserImpl(); return p;

Thanks in advance for helping me.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

千柳 2024-10-09 06:14:16

有几点:

  1. 您的工厂几乎肯定应该使用一个来实例化,而不是一个工具对象。让某人创建一个 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?扩展 Tool> 并添加一个受保护的方法,允许其他类注册映射。

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

A couple of things:

  1. Your factory should almost certainly take a class to instantiate, rather than a Tool object. Having someone create a Parser to pass into your method in order to get a Parser is a bit chicken-and-egg.
  2. I don't know if you're allowed to have generic parameters for methods that are wildcards; I presume not since this would be nonsensical and pointless. When you parameterise a method, you need to give the generic parameter a name so that you can refer to it later on.

Putting these together, your factory method might look more like this:

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

If you want to restrict the type of toolClass to be an interface, you can't do this at compile-time, but you can of course introduce a runtime check toolClass.isInterface().

By the way, this static hardcoded switching isn't very nice in general. To my mind, it would be nicer to put the class-to-constructor relationship in a Map and look up the construction process dynamically. Maybe even store the value as a Callable<? extends Tool> and add a protected method allowing other classes to register mappings.

That's not to say that your current version doesn't work, just that it doesn't scale very well, and right now I don't think it's doing much to justify having a separate factory rather than the caller simply invoking toolClass.newInstance() themselves.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文