填充不相关类中的公共字段的框架

时间:2013-05-16 17:22:37

标签: java

我正在尝试编写一个框架来处理与外部库及其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是唯一的普通类。我想到的各种选择是:

  • 每种类型的单独方法。这样做很快,但代码重复会令人沮丧。
  • 我可以对每个类型进行子类化,并让它们实现一个通用接口。虽然这可行,但创建70多个子类然后修改代码以使用它们而不是原始的消息传递类是一个过头的桥梁。
  • 反射。可行,但我希望它太慢(性能是一个问题)

鉴于这些,每个人的单独方法似乎是我最好的选择,但我希望有更好的选择。

3 个答案:

答案 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多个源文件,同时保留第二个项目符号中方法的好处。