2

虽然 C# 支持 Java 中的委派和事件,但我们必须使用匿名内部类进行绑定,否则使用反射代码http://oatv.com/pub/a/onjava/2003/05/21/delegates.html。在该页面的评论中有关于 CGLib Multicast Delegates 的提示,但谷歌代码似乎不知道该类的任何示例代码。有没有人有一个工作示例的链接,其他人触手可及?

4

1 回答 1

1

我知道这个问题很老,但也许有一天有人想知道同样的事情。对于类似普通C#的委托,您可能会使用MethodDelegate,而不是MulticastDelegate. 假设,我们有一个简单的 Java POJO bean:

public class SimpleBean {
  private String value;
  public String getValue() {
    return value;
  }
  public void setValue(String value) {
    this.value = value;
  }
}

然后我们可以像这样创建一个检测(非反射)委托:

public static interface BeanDelegate {
  String getValueFromDelegate();
}

@Test
public void testMethodDelegate() throws Exception {
  SimpleBean bean = new SimpleBean();
  bean.setValue("Hello world!");
  BeanDelegate delegate = (BeanDelegate) MethodDelegate.create(
      bean, "getValue", BeanDelegate.class);
  assertEquals("Hello world!", delegate.getValueFromDelegate());
}

这个例子有几点需要注意:

  • 工厂方法MethodDelegate#create只采用一个方法名称作为其第二个参数。这是MethodDelegate将为您代理的方法。

  • 必须有一个没有为对象定义参数的方法,该方法作为其第一个参数提供给工厂方法。因此,MethodDelegate它并不像它可能的那么强大。

  • 第三个参数必须是一个只有一个参数的接口。实现了这个MethodDelegate接口并且可以被强制转换为它。调用该方法时,它将调用作为第一个参数的对象的代理方法。

有一些缺点/陷阱:

  • CGlib 为每个代理创建一个新类。最终,这将填满你的永久代堆空间。(从长远来看,这可能会导致问题。)

  • 您不能代理带参数的方法。(这很糟糕。)

  • 如果您的接口接受参数,则方法委托将根本无法正常工作而不会引发异常(返回值将始终为null)。如果您的接口需要另一种返回类型(即使那更通用),您将获得一个IllegalArgumentException. (这很奇怪。)

MulticastDelegate作品有点不同。这次我们需要一个 bean,它实际上用一个方法实现了一个接口:

public class SimpleMulticastBean implements DelegatationProvider {
  private String value;
  public String getValue() {
    return value;
  }
  public void setValue(String value) {
    this.value = value;
  }
}

public interface DelegatationProvider {
  void setValue(String value);
}

这一次,DelegatationProvider在示例中调用的接口必须提供一个方法(如前所述)。此接口必须由添加到此委托代理的任何对象实现。这可以按如下方式完成:

@Test
public void testMulticastDelegate() throws Exception {
  MulticastDelegate multicastDelegate = MulticastDelegate.create(
      DelegatationProvider.class);
  SimpleMulticastBean first = new SimpleMulticastBean();
  SimpleMulticastBean second = new SimpleMulticastBean();
  multicastDelegate = multicastDelegate.add(first);
  multicastDelegate = multicastDelegate.add(second);

  DelegatationProvider provider = (DelegatationProvider)multicastDelegate;
  provider.setValue("Hello world!");

  assertEquals("Hello world!", first.getValue());
  assertEquals("Hello world!", second.getValue());
}

同样,这种实现也有其缺点:

  • 对象需要实现单方法接口。这对于第三方库来说很糟糕,并且当您使用 CGlib 来做一些魔术时,这种魔术会暴露给普通代码时会很尴尬。此外,您可以轻松实现自己的委托(虽然没有字节码,但我怀疑您是否比手动委托更胜一筹)。

  • 当您的委托返回一个值时,您将只收到您添加的最后一个委托的值。所有其他返回值都将丢失(但在某个时候由多播委托检索)。

进一步阅读:我受到启发,并在一篇博客文章中总结了我所知道的关于 cglib 的一切

于 2013-11-13T17:43:55.517 回答