我有一个具有许多可能实现的接口。应该在运行时选择正确的实现。因此,Reflection似乎是解决方案。
我用一个限定符注释了这些类,限定符的参数是一个枚举。
那么,是否有可能在运行时使用反射通过将正确的枚举传递给注释来获得正确的实现类?
但是,如果有其他方法,则反射不是强制性的。
首先,这里是枚举:
public enum CATEGORY {
A,B,C;
}
然后,这里是接口:
public interface GenericI{
void method1(CATEGORY arg);
// some other methods
}
现在,这里有带注释的实现:
@MyAnnotation(CATEGORY.A)
public class impl1 implements GenericI{
void method1(CATEGORY arg){
// some work here
}
}
@MyAnnotation(CATEGORY.B)
public class impl2 implements GenericI{
void method1(CATEGORY arg){
// some work here
}
}
最后,代理在某种程度上,使用注释和枚举动态地选择正确的实现(可能它不应该实现GenericI ??):
public class MyProxy implements GenericI {
// Here we must be able to select the right implementation
}
反射是一个答案,但是您需要从类路径中获取所有类,并检查它以找到接口的实现。
你可以使用这个反射库,并获得所有这样的实现(如果你的接口名称是MyInterface):
Reflections reflections = new Reflections("your.base.package", new SubTypesScanner(), new TypeAnnotationsScanner());
Set<Class<T extends MyInterface>> classes = reflections.getSubTypesOf(MyInterface.class);
for (Class<T extends MyInterface> c : classes) {
check if c is the rigth implementation!.
}
如果你不想使用外部库,你可以使用Java反射API,并扫描所有包,类似于(参见使用检测的答案):
Instrumentation inst = InstrumentHook.getInstrumentation();
for (Class<?> c: inst.getAllLoadedClasses()) {
if (MyInterface.class.isAssignableFrom(c)) {
check if c is the rigth implementation!.
}
}
第一个选项允许您将Reflections
对象保存为xml,因此组件扫描被保存并且只执行一次。
检查clazz
是否有Qualifier
,您可以使用:
if (c.isAnnotationPresent(Qualifier.class)) {
bingo!.
}
or是注释的一个属性:
if (c.isAnnotationPresent(Qualifier.class)) {
Qualifier q = c.getAnnotation(Qualifier.class);
if (q.theRight()) {
bingo!
}
}
我建议您看看FactoryProblem
是否适用于您的问题,始终选择Factory
而不是Reflection
。
示例"proxy":
public class MyProxy implements GenericI {
Map<Category, GenericI> generics;
public MyProxy() {
Reflections reflections = new Reflections("your.base.package", new SubTypesScanner(), new TypeAnnotationsScanner());
Set<Class<T extends MyInterface>> classes = reflections.getSubTypesOf(MyInterface.class);
generics = new HashMap<Category, GenericI>();
for (Class<T extends MyInterface> c : classes) {
map.put(c.getAnnotation(MyAnnotation.class).value(), c.newInstance());
}
}
void method1(CATEGORY arg){
map.get(arg).method1(arg);
}
}
这是非常沉重和过于复杂的,如果你使用这个,请添加广泛的测试,并使MyProxy
为单例。
如果您使用IOC框架:
@Component
public class MyProxy implements GenericI {
@Autoriwed // If spring
List<GenericI> generics;
@Inject @Any // If CDI
private Instance<GenericI> services;
Map<Category, GenericI> generics;
@PostConstruct
void makeMap() {
generics = new HashMap<>();
for (GenericI component : generics) {
generics.put(
component.getClass().getAnnotation(MyAnnotation.class).value(),
component);
}
}
void method1(CATEGORY arg){
map.get(arg).method1(arg);
}
}
我假设你不知道所有可能的子类