在Java中将类A(和所有子类)映射到类B的实例的字典
在Java中实现strategy patterny时,有一个常见的问题是将输入数据类型映射到特定算法的实例
例如,我们可以创建一张地图:
map.put(Apple.class, new AppleHandler());
map.put(Orange.class, new OrangeHandler());
并在运行时为给定数据类型解析正确的处理程序:
Apple a = new Apple();
map.get(a.getClass()).handle(a);
问题:在Guava/ApacheCommons等此类映射库中是否有任何Map<Class<A>, B>
实现,可以处理多态类型强>
例如,对于上述映射,其工作原理如下(假设GreenApple扩展了Apple):
map.get(Apple.class) == map.get(GreenApple.class);
我知道我可以编写跨越层次结构的实现,但我想问的是OTS解决方案
# 1 楼答案
我已经通过注释解决了类似的问题,如
通过这种方式,我得到了一个处理程序类,而不是处理程序本身,但在我的例子中,这很好。您可以使用
Class#newInstance
或依赖项注入来获取处理程序实例另一种可能是像这样的查找循环
这适用于超类,但不适用于接口。可以对它们进行扩展,但之后可能会遇到the diamond problem
我做过一次,钻石问题对我来说没有问题,因为我的经纪人被严格地排在了优先顺序上。我的最终优化解决方案是使用
ConcurrentMap<Class<?>, <Class<AbstractHandler>>>
,每次遇到新类时我都会更新它# 2 楼答案
最简单的解决方案是简单地为具有多个类的处理程序添加多个映射项:
这种方法的一些注意事项包括
A
的新类并在运行时提供它们,那么您也需要某种方法来注册它们(例如,在初始化时扫描类路径,提供某种类型的注册API供外部代码使用,或者如果请求的键不在映射中,则添加对遍历层次结构的支持)李>但是,如果您可以控制源代码,则可以在编译时在类本身中进行此“映射”:
现在,只需调用类
A
的getHandler()
方法,就可以获得类A
的任何实例的处理程序。由于getHandler()
是合同的一部分,定义A
新类的外部源也必须实现它如果无法更改类型
A
的源或不想更改(到separate concerns,等等),则可以引入新的类型包装A
,以使用decorator pattern定义映射