我正在尝试编写一个框架来处理与外部库及其API的接口。作为其中的一部分,我需要填充在许多(70个)可能的消息类中的每一个中具有相同名称和类型的头字段。不幸的是,不是让每个消息类派生自包含头字段的公共基类,而是每个消息类都是完全独立的。
如玩具示例:
public class A
{
public Header header;
public Integer aData;
}
public class B
{
public Header header;
public Long bData;
}
如果他们设计得很清楚A和B派生自包含标题的基类,我可以这样做:
public boolean sendMessage(BaseType b)
{
b.header = populateHeader();
stuffNecessaryToSendMessage();
}
但就目前而言,Object是唯一的普通类。我想到的各种选择是:
鉴于这些,每个人的单独方法似乎是我最好的选择,但我希望有更好的选择。
答案 0 :(得分:2)
我建议你以下。创建一组您想要的接口。例如
public interface HeaderHolder {
public void setHeader(Header header);
public Header getHeader();
}
我希望你的课程能够实现它们,即你的课程B
被定义为
class B implements HeaderHolder {...}
不幸的是,事实并非如此。现在问题!
创建外观:
public class InterfaceWrapper {
public <T> T wrap(Object obj, Class<T> api) {...}
}
您可以使用动态代理在此阶段实施它。是的,动态代理使用反射,但现在就忘了这一点。
完成后,您可以使用InterfaceWrapper
,如下所示:
B b = new B();
new IntefaceWrapper().wrap(b, HeaderHolder.class).setHeader("my header");
正如您现在所看到的,您可以将标题设置为您想要的任何类(如果它具有适当的属性)。完成后,您可以检查您的表现。当且仅当在动态代理中使用反射是瓶颈时,才将实现更改为代码生成(例如,基于自定义注释,包名称等)。有很多工具可以帮助您做到这一点,或者您可以自己实现这样的逻辑。关键是您可以随时更改IntefaceWrapper
的实现,而无需更改其他代码。
但要避免过早优化。这些天反思非常有效。 Sun / Oracle努力实现这一目标。例如,他们动态创建类并缓存它们以使反射更快。因此,考虑到全流程,反射呼叫不会占用太多时间。
答案 1 :(得分:1)
我所知道的唯一一个可以执行此操作的库Dozer。它确实使用了反射,但好消息是,测试它是否比编写自己的反射代码要慢,以发现它很慢会更容易。
默认情况下,dozer会在两个对象上调用相同的getter / setter,即使它们完全不同。您可以使用更复杂的方式对其进行配置。例如,您也可以告诉它直接访问这些字段。您可以为它提供一个自定义转换器,将Map转换为List,就像这样。
您可以只使用一个已填充的实例,或者甚至是您自己的BaseType
并说出dozer.map(baseType, SubType.class);
答案 2 :(得分:1)
如何在项目的构建时间内动态生成这70多个子类?这样,您就不需要维护70多个源文件,同时保留第二个项目符号中方法的好处。