у кого-нибудь есть пример кода для использования cglib MulticastDelegate для выполнения чего-то вроде событий C #? - PullRequest
2 голосов
/ 11 ноября 2010

В то время как C # имеет языковую поддержку делегирования и событий в Java, мы должны либо использовать анонимные внутренние классы для привязки, либо использовать код отражения http://oatv.com/pub/a/onjava/2003/05/21/delegates.html. На этих страницах комментариев есть подсказка о делегатах CGLib Multicast, но кодах Google похоже, не знает ни о каком примере кода для этого класса. У кого-нибудь есть ссылка на рабочий пример, а у кого-то есть ссылка?

1 Ответ

1 голос
/ 13 ноября 2013

Я знаю, что этот вопрос старый, но, возможно, кто-то задается вопросом об одном и том же. Для обычного 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 работает немного по-другому. На этот раз нам нужен компонент, который на самом деле реализует интерфейс с помощью одного метода:

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 для выполнения magic , когда эта магия подвергается действию normal code . Кроме того, вы могли бы легко реализовать свой собственный делегат (без байт-кода, хотя я сомневаюсь, что вы так много выиграете над делегированием вручную).

  • Когда ваши делегаты возвращают значение, вы получите только значение последнего добавленного вами делегата. Все остальные возвращаемые значения теряются (но извлекаются в какой-то момент делегатом многоадресной рассылки).

Для дальнейшего чтения : я вдохновился и обобщил все, что я знаю о cglib, в статье блога .

...