您可以将所有类放在一个特定的包中,然后扫描该目录中的类文件,加载它们,并跟踪扩展Monster
. 您甚至可以定义一些自定义注释来帮助管理它,例如@IgnoreMonster
暂时禁用某些注释而无需更改文件的位置。这类似于 Hibernate 扫描源以查找实体映射的方式。
这是一个例子。所有 Monster 类都放在 package 中dload.monsters
。首先,这是我用于此示例的基类:
package dload.monsters;
public abstract class Monster {
public abstract String getName ();
}
然后,MonsterFactory
它扫描包中的所有类dload.monsters
(抱歉有点草率,我略过了异常处理):
package dload.monsters;
import java.io.*;
import java.net.*;
import java.util.*;
public class MonsterFactory {
private static final List<Class<? extends Monster>> monsterClasses = new ArrayList<Class<? extends Monster>>();
private static final Random random = new Random();
@SuppressWarnings("unchecked") // <- for monsterClasses.add((Class<? extends Monster>)cls);
public static void loadMonsters () throws Exception {
// in this example, Monster is in the same package as the monsters. if
// that is not the case, replace "." with path relative to Monster.
File folder = new File(Monster.class.getResource(".").toURI());
for (File f : folder.listFiles()) {
if (f.getName().endsWith(".class")) {
String name = f.getName().split("\\.")[0];
// replace "dload.monsters." below with package monsters are in
Class<?> cls = ClassLoader.getSystemClassLoader().loadClass("dload.monsters." + name);
// if Monster is not in same package as monsters, you can remove
// cls.equals(Monster.class) check. this check makes sure the loaded
// class extends Monster, but is not the Monster class itself (since
// its also in that package).
if (Monster.class.isAssignableFrom(cls) && !cls.equals(Monster.class)) {
System.out.println("Found " + cls.getSimpleName());
monsterClasses.add((Class<? extends Monster>)cls);
}
}
}
// at this point all Class's for monsters are in monsterClasses list.
}
public static Monster randomMonster () throws Exception {
// choose a class at random
int n = random.nextInt(monsterClasses.size());
Class<? extends Monster> cls = monsterClasses.get(n);
// instantiate it
return cls.newInstance();
}
}
然后,当你想使用它时:
public static void main (String[] args) throws Exception {
// load monsters; only need to do this once at startup
MonsterFactory.loadMonsters();
// create 10 random monsters
for (int n = 0; n < 10; ++ n) {
Monster m = MonsterFactory.randomMonster();
System.out.println("name is " + m.getName());
}
}
请注意,您可以随时查看怪物的Class
相关注释。
另一种选择是,如果类已经加载(如果它们从未被使用或显式加载,则不会加载) Instrumentation.getAllLoadedClasses()
用于获取当前加载的所有类的列表,然后扫描所有类以查找那些可分配给Monster
.
注意:我确实觉得有一种更简洁的方法来进行实际扫描,而且我还没有在 JAR 中测试过。欢迎提出建议。
话虽如此,如果怪物的行为可以完全由数据定义,我也支持并推荐上述数据驱动的方法。