动态选择一个班级

时间:2013-04-12 07:52:54

标签: java inheritance interface

首先我不知道如何打电话给我的问题,所以任何有关更好标题的建议请告诉我。

我想创建一个接口,以便其他人可以添加他们的实现,然后在运行时决定使用哪个实现。

即。 我创建了一个界面“食物”,并存在2个实现“早餐”和“午餐”。在实现中,两者具有相同的方法名称和相同的参数,我想让用户在运行时调用它们中的任何一个。 “makeFood()使用Breakfast”或“makeFood()使用午餐”。

一种可能性是仅编译一个实现,但如果将来必须使用其他实现,则需要删除.class文件。

或者我应该使用某种类型的继承?

另外(不是优先权): 我不知道实现类名,所以有人可以创建“晚餐”或“secondBreakfast”。这会让我陷入另一个困境,如果用户请求尚未实现的“类”该怎么办:S我总是可以假设用户将知道哪些实现可用。

3 个答案:

答案 0 :(得分:4)

这听起来像战略模式将满足您的需求(GOF - http://en.wikipedia.org/wiki/Strategy_pattern)。

我不清楚你想要它有多动态。有两个接口实现,以及一个选择之间的选择器方法是最简单的。但是你也可以动态地动态生成接口的实现,这可能会在这里过度杀死你。无论哪种方式,策略模式都可以抽象出这种复杂性,并使您能够根据所需的任何运行时条件选择不同的行为。

这是一个动态加载类的示例,假设您已经知道完全限定的类名,并且该对象具有无arg构造函数:

Class c = Class.forName("java.lang.Object");
Object o = c.newInstance();

System.out.println( "o = " + o );

此案例需要捕获的错误包括:InterruptedException,ClassNotFoundException,IllegalAccessException,InstantiationException;很多,但只是以同样的方式处理它们并拒绝用户选择。

如果你需要一个带参数的构造函数,那么:

Class c = Class.forName("java.lang.String");
Constructor cons = c.getConstructor( String.class ); // the args here are the expected types for the constructor that you require on the class
String s = (String) cons.newInstance( "hello" );

这将添加更多必须捕获的异常:InterruptedException,ClassNotFoundException,IllegalAccessException,InstantiationException,NoSuchMethodException,InvocationTargetException。但是,再次以与以前相同的方式拒绝用户选择。

答案 1 :(得分:1)

如果您不知道类名并希望了解所有可用的类,则需要在运行时获取接口的所有实现。 这可以通过思考来实现:http://code.google.com/p/reflections/

查看方法getSubTypesOf

如果您希望用户提供自己的实现并使用此实现,您有不同的选择:

1)在启动时读取提供的Jar,并使用依赖注入和预先配置的安装程序(例如使用Spring)。用户可以在启动应用程序之前将完全qialified类名写入设置。

2)使用插件机制,如ServiceLoader:http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html或JSPF:http://code.google.com/p/jspf/

或者如果你想在运行时阅读新的实现,你可以使用OSGi:http://en.wikipedia.org/wiki/OSGi(看看Apache Karaf,Eclipse Equinox和Apache Felix)。

答案 2 :(得分:0)

您似乎正在描述Java的interface。例如:

Food.java:

interface Food {
    void makeFood();
}

Breakfast.java:

class Breakfast implements Food {
    void makeFood() { System.out.println("Breakfast."); }
}

Lunch.java:

class Lunch implements Food {
    void makeFood() { System.out.println("Lunch."); }
}

正如您所说,我们有Food的两种不同实现。现在,我们可以通过构造任一实现类来实例化Food对象:

Food myFood = new Breakfast();

Food myFood = new Lunch();

没有删除文件或类似内容。希望能让事情变得更加清晰。