【问题标题】:Programmatically implementing an interface that combines some instances of the same interface in various specified ways以编程方式实现一个接口,该接口以各种指定方式组合同一接口的某些实例
【发布时间】:2011-02-22 14:31:59
【问题描述】:

实现以各种指定方式组合同一接口的某些实例的接口的最佳方法是什么?我需要为多个接口执行此操作,并且我希望最大限度地减少样板代码并仍然实现良好的效率,因为我需要它用于关键的生产系统。

这是问题的草图。

抽象地说,我有一个通用组合器类,它接受实例并指定各种组合器:

class Combiner<I> {
   I[] instances;

   <T> T combineSomeWay(InstanceMethod<I,T> method) {
     // ... method.call(instances[i]) ... combined in some way ...
   }

   // more combinators
}

现在,假设我要实现以下接口:

Interface Foo {
  String bar(int baz);
}

我想得到这样的代码:

class FooCombiner implements Foo {
  Combiner<Foo> combiner;

  @Override 
  public String bar(final int baz) {
    return combiner.combineSomeWay(new InstanceMethod<Foo, String> {
      @Override public call(Foo instance) { return instance.bar(baz); } 
    });
  }
}

现在,如果接口有很多方法,这很快就会变得冗长而曲折。我知道我可以使用 Java 反射 API 中的动态代理来实现这样的接口,但是通过反射访问方法要慢一百倍。那么在这种情况下,样板和反射的替代方案是什么?

【问题讨论】:

  • 这是一个相当大的标题!

标签: java reflection code-generation proxy-classes


【解决方案1】:

我会建议使用动态代理 - 现在它真的比常规方法调用慢得多吗 - 我听说反射在幕后有相当多的魔力来加速重复的方法调用。 (如果它慢 100 倍,你确定你会注意到吗?好的,只要重新阅读你的问题 - 你会注意到的!)

否则,您的问题基本上有解决方案:使用 Command 对象将每个方法包装在您的界面中。然后,您可以将接口集合中的每个实例传递给命令对象进行处理。

当然,如果您有勇气和冒险精神,您可以使用 cglib、javassist 或其他 dynamic bytecode generator 生成命令对象的实现,以及使用动态类生成的组合器接口的实现。这样可以避免样板。

您也可以在方面取得一些成功,尤其是在编译时或加载时编织方面的方面,因此您可以避免反射开销。抱歉,我不能提供详细信息。

【讨论】:

  • 我最终使用了动态代理,它更干净。此外,减速并不明显,因为无论如何方法访问速度都很快。
【解决方案2】:

你可以反转你的组合器:

@Override
public String bar(int baz)
{
    //for (Foo f:combiner.combineSomeWay())// returns Iterator<Foo>
    for (Foo f:combiner) //combiner must implement Iterable<Foo> or Iterator<Foo>
    {
        // In case of several ways to combine
        // add() method should call some temp object
        // in combiner created (or installed) by 
        // combineSomeWay.
        // The best temp object to use is Iterator
        // returned by combiner.combineSomeWay();
        combiner.add(f.bar(baz));// or addResult, or addCallResult
    }
    // clear (or uninstall) temp object and result
    // thats why get* method 
    // name here is bad.
    return combiner.done(); 
}

不是单行的,但更容易理解。但是,如果您的方法抛出异常,那将更加复杂。您将需要 try/catch 块和 addException 方法。

【讨论】:

  • 不错的主意,但在我的情况下它不起作用,因为我希望组合器决定是否调用该方法(例如,一个组合器只调用第一个实例并忽略其他实例)。无论如何,谢谢你的好转。
  • 这正是我在这里使用迭代器而不是集合的原因。当Combiner需要调用方法时,必须通过迭代器提供对象,它可以根据add方法的参数来决定Iterator返回的下一个元素。延续会大大简化组合器,但 java 还不支持它们。
  • 啊,这很聪明...无论如何,在每个方法中都有一个 for 循环仍然是非常样板的。但很好的技巧。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-20
  • 1970-01-01
  • 2017-01-03
  • 1970-01-01
  • 2012-05-16
  • 2020-12-09
  • 2015-05-01
相关资源
最近更新 更多