Используйте классные категории для добавления динамических свойств

Продолжая эту запись в блоге, я пытаюсь используйте категорию для создания простого DSL для использования с классами javax.measure (JSR-275) (аналогично TimeCategory для временных интервалов)

Однако я не хочу добавлять шаблонный код для каждого из возможных доступных методов (getMeter, getMilliMeter, getKelvin, getSecond и т. д.). Я думал, что переопределение метода getProperty(String) сработает, но, увы, похоже, что метод getProperty, определенный в категории, не используется при прямом доступе к свойству.

Вот некоторый упрощенный код для демонстрации: import javax.measure.quantity.Length; импортировать javax.measure.unit.Unit; импортировать javax.measure.Measure;

@Category(Number)
class LengthCategory {      
    public Measure<BigDecimal, Length> getProperty(String unit){
        return Measure.valueOf(this,Unit.valueOf(unit));
    }
}

use(LengthCategory){
    println 3.getProperty("m")  // this works
    println 3.m                 // this reports a non-exisiting property
    prinlln 3.'m'               // as does this
}

Предполагая, что другие методы динамического добавления свойств к объекту среды выполнения (например, Expando, создание подклассов GroovyInterceptible, примеси и другие манипуляции с метаклассами) нежизнеспособны, и мне бы действительно не пришлось вручную кодировать геттеры для каждой возможной комбинации единиц и префиксов SI. Очевидно, есть и другие способы создания DSL для измерений, но мне все же хотелось бы понять, почему этот метод не работает.

Может ли кто-нибудь объяснить, почему метод getProperty категории не переопределяет использование .propertyName? Я явно упускаю что-то важное в разрешении имен свойств с использованием метакласса во время выполнения.


person RudolphEst    schedule 26.02.2013    source источник


Ответы (3)


Я не знаю, почему getProperty не работает с категориями. Но вы можете определить для них метод get, который делает в основном то же самое (я думаю). Это работает:

@Category(Number)
class LengthCategory {      
    def get(String unit) {
        "$this $unit"
    }
}

use (LengthCategory) {
    println 3.m   // 3 m
    println 3.'m' // 3 m
}
person epidemian    schedule 26.02.2013
comment
Спасибо, это именно то, что я хочу, но я все же хотел бы знать, почему реализация getProperty (имя строки) в категории не работает. - person RudolphEst; 27.02.2013

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

Вы можете расширить Integer, используя свойства только для чтения, используя версию метода свойства. Вы даже можете сделать его доступным для записи, включив метод set. Однако, похоже, нет способа сохранить переданное значение, кроме как в статической переменной, и это в конечном итоге влияет на все целые числа.

Пример:

$ cat catprop
#!/usr/local/bin/groovy

@Category(Integer)
class CatInteger {
  private static String str = "default"
  public static String setN(Integer i, String _str) { str = _str }
  public static String getN(Integer i) { return str }
}

use (CatInteger) {
  3.n = "333a"
  println "3.n is " + 3.n

  3.n = "333b"
  println "3.n is " + 3.n

  4.n = "444"
  println "4.n is " + 4.n
  println "3.n is " + 3.n
}
$ catprop
3.n is 333a
3.n is 333b
4.n is 444
3.n is 444
$

Обратите внимание, что в последней строке 3.n возвращается «444», потому что сохраненное поле является статическим. Я предполагаю, что можно было бы использовать частную HashMap и хранить значение для каждого доступного Integer, но это слишком уродливо, чтобы созерцать.

Другой возможностью было бы использование getProperty() и setProperty() интерфейса MetaClass. Однако я не изучал это, поэтому не знаю, сработает это или нет (просто мысль).

person Barry Holroyd    schedule 14.10.2016

Хороший ответ, но не уверен, если вы все еще хотите использовать JSR-275 теперь, когда JSR-363 является окончательным? ;-)

person Werner Keil    schedule 28.10.2016
comment
Хороший вопрос, но это довольно старый вопрос. Новая шапка JSR не была ратифицирована, когда ее изначально просили. - person RudolphEst; 30.10.2016
comment
Это правильно. Он ссылался на последний пример/ответ, не уверен, почему он оказался над ним? Мы предлагаем поддержку Groovy для JSR 363 по адресу github.com/unitsofmeasurement/uom. -spaces/дерево/мастер/. Подобно тому, что было сделано для JSR 354 (JavaMoney) раньше. - person Werner Keil; 31.10.2016