注册类的不同实现

时间:2013-11-22 09:52:51

标签: 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 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没有直接在任何地方使用,所以没有加载类,也没有执行静态块。我可以通过多种方式明确加载它们,但关键是要有“未知”的多个实现。

有些人可能认为解决方案是没有未知的实现,但这确实是我的问题的必要条件。

2 个答案:

答案 0 :(得分:0)

如果他们以某种方式注册到基类,您可以加载“未知”注册(服务)。各种运行时容器提供了各种注册服务的方法,但JDK6以来JDK中可用的标准方法是使用ServiceLoader.load(Foo.class)(http://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html处的javadoc)。我使用这种技术来实现一些我称之为可注射单例的东西(其中单例API不知道其实际实现的位置,请参阅http://wiki.apidesign.org/wiki/Injected_Singleton),但该技术也可以在您的示例中使用。

请确保 META-INF /服务/ your.pkg.Foo 文件在您的JAR中,内容提到以下两行(可以使用@ org.openide.util.lookup.ServiceProvider注释生成,但不必生成):

your.pkg.FooA
your.pkg.FooB

然后你可以使用

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

答案 1 :(得分:0)

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