Классы Java с динамическими полями

Я ищу умные способы создать динамические классы Java, который является классами, где можно добавить/удалить поля во времени выполнения. Сценарий использования: у Меня есть редактор, где пользователи должны смочь добавить поля к модели во времени выполнения или возможно даже создать целую модель во времени выполнения.

Некоторые цели дизайна:

  • Безопасный с точки зрения типов без бросков, если это возможно, для пользовательского кода, который работает над динамическими полями (что код прибыл бы из плагинов, которые расширяют модель непредвиденными способами).
  • Хорошая производительность (может Вы биться HashMap? Возможно, используйте массив и присвойте индексы полям во время установки?)
  • Полевое "повторное использование" (т.е. если Вы используете тот же тип поля в нескольких местах, должно быть возможно определить его однажды и затем снова использовать его).
  • Вычисляемые поля, которые зависят от значения других полей
  • Сигналы должны быть отправлены, когда поля изменяют значение (не обязательно через Бобы API)
  • "Автоматические" родительские дочерние отношения (то, когда Вы добавляете дочерний элемент к родителю, затем родительский указатель в ребенке, должно быть установлено для "свободного").
  • Легкий понять
  • Простой в использовании

Обратите внимание, что это, "думают вне кругового" вопроса. Я отправлю пример ниже для получения Вас в настроении :-)

6
задан 2 revs, 2 users 100% 29 April 2012 в 15:11
поделиться

3 ответа

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

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

Лучшее, что вы можете сделать, - это иметь интерфейс с набором методов, например String getStringValue (String field) , int getIntValue (String field) и так далее. И, конечно, вы можете сделать это только для заранее определенного набора типов. Любое поле, тип которого не входит в этот набор, потребует преобразования типа.

2
ответ дан 17 December 2019 в 00:03
поделиться

Итак, в основном вы пытаетесь создать новый вид объектной модели с более динамическими свойствами, немного похожий на динамический язык?

Возможно, стоит взглянуть на исходный код Rhino (т.е. Javascript, реализованный на Java), который сталкивается с аналогичной проблемой реализации системы динамических типов на Java.

Из всего вышесказанного, я подозреваю, что вы обнаружите, что внутренние HashMaps в конечном итоге работают лучше для ваших целей.

Я написал небольшую игру (Tyrant - доступен источник GPL), используя подобную динамическую объектную модель с использованием HashMaps, она отлично работала, и производительность не была проблемой. Я использовал несколько трюков в методах get и set, чтобы позволить динамические модификаторы свойств, я уверен, что вы можете сделать то же самое для реализации ваших сигналов и отношений родитель/ребенок и т.д.

[EDIT] Смотрите в источнике BaseObject, как это реализовано.

1
ответ дан 17 December 2019 в 00:03
поделиться

Очевидный ответ - использовать HashMap (или LinkedHashMap , если вам нужен порядок поля). Затем вы можете добавить динамические поля с помощью метода get (String name) и set (String name, Object value) .

Этот код может быть реализован в общем базовом классе. Поскольку существует всего несколько методов, также просто использовать делегирование, если вам нужно расширить что-то еще.

Чтобы избежать проблемы с приведением типов, вы можете использовать типобезопасную карту объектов :

    TypedMap map = new TypedMap();

    String expected = "Hallo";
    map.set( KEY1, expected );
    String value = map.get( KEY1 ); // Look Ma, no cast!
    assertEquals( expected, value );

    List<String> list = new ArrayList<String> ();
    map.set( KEY2, list );
    List<String> valueList = map.get( KEY2 ); // Even with generics
    assertEquals( list, valueList );

Уловка здесь - это ключ, который содержит информацию о типе:

TypedMapKey<String> KEY1 = new TypedMapKey<String>( "key1" );
TypedMapKey<List<String>> KEY2 = new TypedMapKey<List<String>>( "key2" );

Производительность будет в порядке.

Повторное использование поля - это использование того же типа значения или расширение ключевого класса типобезопасной карты объектов с помощью дополнительных функций.

Вычисляемые поля могут быть реализованы с помощью второй карты, в которой хранятся экземпляры Future , которые выполняют вычисления.

Поскольку все манипуляции производятся всего двумя (или, по крайней мере, несколькими) методами, отправка сигналов проста и может выполняться любым удобным для вас способом.

Чтобы реализовать автоматическую обработку родительских / дочерних сигналов, установите прослушиватель сигналов для сигнала «установить родительский» дочернего элемента, а затем добавьте дочерний элемент к новому родительскому элементу (и при необходимости удалите его из старого).

Поскольку фреймворк не используется и никаких уловок не требуется, результирующий код должен быть довольно чистым и легким для понимания. Отсутствие использования String в качестве ключей имеет дополнительное преимущество: люди не будут засорять код строковыми литералами.

2
ответ дан 17 December 2019 в 00:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: