Java метапрограммирование

Я работаю над своим первым реальным проектом с Java. Я начинаю устраивать язык, хотя у меня больше опыта работы с динамическими языками.

У меня есть класс, который ведет себя аналогично следующему:

class Single
{
    public void doActionA() {}
    public void doActionB() {}
    public void doActionC() {}
}

И тогда у меня есть класс SingleList, который действует как набор этих классов (в частности, он для библиотеки 2D Sprite, а "действия" - всевозможные преобразования: вращение, сдвиг, масштаб и т.д.). Я хочу иметь возможность сделать следующее:

class SingleList
{
    public void doActionA() {
        for (Single s : _innerList) {
            s.doActionA();
        }
    }

    ... etc ...
}

Есть ли способ просто отложить метод (или известный список методов) каждому члену внутреннего списка? В любом случае, без необходимости конкретно перечислять каждый метод, затем прокручивать каждый внутренний элемент и применять его вручную?

Чтобы сделать вещи немного сложнее, методы имеют разную степень, но все они возвращают тип "void".

Ответ 1

К сожалению, Java не всегда поддерживает создание классов во время выполнения, что вам нужно: SingleList необходимо автоматически обновить с помощью необходимых методов заглушки, чтобы соответствовать классу Single.

Я могу придумать следующие подходы к этой проблеме:

  • Используйте Отражение Java:

    • Плюсы:
      • Он легко доступен на языке Java, и вы можете легко найти документацию и примеры.
    • Минусы:
      • Класс SingleList больше не будет совместим с интерфейсом класса Single.
      • Компилятор Java и любые IDE, как правило, не могут помочь с методами, вызванными отражением. Ошибки, которые были бы уловлены компилятором, обычно преобразуются в исключения времени выполнения.
      • В зависимости от вашего варианта использования вы также можете заметить заметное ухудшение производительности.
  • Используйте систему сборки вместе с каким-то генератором исходного кода для автоматического создания файла SingleList.java.

    • Плюсы:
      • Как только вы его настроите, вам больше не придется иметь дело с этим.
    • Минусы:
      • Настройка этого уровня имеет определенную степень сложности.
      • Вам придется отдельно убедиться, что класс SingleList, загруженный в любой JVM - или ваш IDE, если на то пошло - фактически соответствует загруженному классу Single.
  • Решить эту проблему вручную - создание интерфейса (например, SingleInterface) или базовый абстрактный класс для использования обеими классами должны помочь, поскольку любая достойная среда IDE укажет на нереализованные методы. Надлежащая архитектура классов сводит к минимуму дублированный код, и ваша среда IDE может помочь в создании частей шаблона.

    • Плюсы:
      • Кривая настройки не будет достигнута.
      • В вашей среде IDE всегда будет отображаться правильный набор классов.
      • Архитектура класса обычно улучшается после.
    • Минусы:
      • Все в порядке.
  • Используйте библиотеку генерации байт-кода, например Javassist или BCEL для динамического создания/изменения класса SingleList на лету.

    • Плюсы:
      • Этот метод чрезвычайно эффективен и может сэкономить много времени в долгосрочной перспективе.
    • Минусы:
      • Использование библиотек генерации байт-кода обычно не тривиально, а не для слабонервных.
      • В зависимости от того, как вы пишете свой код, вы также можете иметь проблемы с вашей IDE и обработкой динамических классов.