Java 注册类的不同实现

Java 注册类的不同实现,java,static,dependencies,Java,Static,Dependencies,我想要一个抽象类,比如Foo,它提供了一组由子类实现的api。但我不想让任何人知道哪个是这个子类的实际实例,只想知道它们可以使用静态Foo方法检索。大致上,这些类是这样的: class Foo { protected Hashtable foos = new Hashtable; public static Foo getFoo(String key) { return (Foo) foos.get(key); } public abstra

我想要一个抽象类,比如Foo,它提供了一组由子类实现的api。但我不想让任何人知道哪个是这个子类的实际实例,只想知道它们可以使用静态Foo方法检索。大致上,这些类是这样的:

class Foo {

    protected Hashtable foos = new Hashtable;

    public static Foo getFoo(String key) {
        return (Foo) foos.get(key);
    }

    public abstract void doSomething();

}

class FooA extends Foo {

    static {
        Foo.foos.put("A", new FooA());
    }

    public void doSomething() {
        System.out.println("A FooA instance is doing something!!");
    }

}

class FooB extends Foo {

    static {
        Foo.foos.put("B", new FooB());
    }

    public void doSomething() {
        System.out.println("A FooB instance is doing something!!");
    }

}
其用法如下:

Foo foo = Foo.get("A");
foo.doSomething();
问题在于,由于FooA和FooB没有在任何地方直接使用,因此不会加载类,也不会执行静态块。我可以通过多种方式显式加载它们,但关键是要有“未知”的多个实现

有些人可能认为解决方案是不使用未知的实现,但这确实是我的问题的一个要求。

如果“未知”注册(服务)以某种方式注册到基类,则可以加载它们。各种运行时容器提供了各种注册服务的方法,但JDK中可用的标准方法是使用ServiceLoader.load(Foo.class)(javadoc at)。我使用这种技术来实现一些我称之为可注入单例的东西(单例API不知道它的实际实现在哪里,请参见),但是这种技术也可以在您的示例中使用

只要确定一下 META-INF/services/your.pkg.Foo 文件位于JAR中,内容包括以下两行(可以使用@org.openide.util.lookup.ServiceProvider注释生成,但不必):

然后你可以使用

for (Foo instance : ServiceLoader.load(Foo.class)) { 
    /* do something with instance of FooA and FooB */ 
}

作为替代解决方案(取决于问题的复杂性),使用依赖项注入可能更容易。在这种模式中,您只需定义接口的实现,并为它们分配限定符,然后让DI框架将实际实现“注入”到需要它们的类中。客户机类不仅不知道它们使用的是什么具体实现,而且也不关心如何获得它们,这可以简化很多事情。已经有很多这样的框架(最值得注意的是Spring和Guice),Java5+已经标准化了一组注释,您可以使用它们来定义注入规则

您是否考虑过使用
Class.forName
加载子类?
for (Foo instance : ServiceLoader.load(Foo.class)) { 
    /* do something with instance of FooA and FooB */ 
}