Динамика Groovy

В этой заметке я расскажу о некоторых возможностях Groovy, которые обеспечивают его динамичность. В частности:

Получение списков свойств и методов класса

У каждого объекта есть методы properties и methods, которые возвращают отображения для свойств и методов объекта соответственно. В частности, следующий код распечатывает все свойства и методы объекта:

obj.properties.each{ println it } // Распечатываем свойства
obj.methods.each{ println it } // А теперь методы

Доступ к свойствам и методам через GString

Рассмотрим задачу доступа к полю или методу, имя которого становится известно только в момент выполнения. В Java для этого приходится использовать достаточно недобный механизм Reflection. В Groovy для этой задачи может быть использован GString. В частности, справа от оператора "." может находится экземпляр строки, значение которой будет использоваться для доступа к свойству или методу объекта. Например:

class Person { // Объявляем новый класс
String name; // Объявляем свойство в классе
}

def p = new Person()
def fn = 'name' // Имя свойства
p."$fn" = 'alex' // Записываем в свойство новое значение

Метаклассы

Динамичность языка Groovy обеспечивается особым механизмом вызова методов: при вызове метода проверяется не только его наличие в классе, но и в специальном объекте, называемом метаклассом. При этом, при первом доступе к свойству metaClass объекта, его метакласс замещается специальным, представляющим из себя Expando, о котором я писал ранее. К метаклассу объекта можно получить доступ через поле metaClass объекта. Используя эту особенность, можно добавлять методоы к уже определенным ранее классам. Для этого всего-навсего необходимо определить соответствующий метод в ExpandoMetaClass класса. Например, можно определить новый метод для всех объектов класса String:

String.metaClass.sizeSqr = {
	delegate.size * delegate.size
}

Перехват вызова методов

Особенностью многих динамических языков является возможность вызова "несуществующих" методов, которые перехватываются специальным обработчиком. Groovy также не является исключением: Любой класс может реализовать интерфейс GroovyInterceptable и определить метод invokeMethod, который будет вызываться при любом вызове метода. Например:

class Service {

	def invokeMethod( String method, args ) {
		println "Called $method"
	}
}

s = new Service()
s.doSomething() // Будет напечатано "Called doSomething"
Второй вариант перехвата методов - добавление метода invokeMethod в метакласс объекта.

Категории

Модификации метаклассов активны на протяжении всего выполнения программы, однако иногда нужен более контролируемый способ добавления методов к классам. Для этого, в Groovy имеется понятие категорий. Категории позволяют ограничить модификацию классов блоком кода. Категория в Groovy - это класс, содержащий статические методы, расширяющие другие классы. Например, рассмотрим класс:

class PersistenceCategory {

	static void save( Object o ) {
		// Реализация сохранения объекта
	}

	static void load( Object o ) {
		// Реализация загрузки объекта
	}
}
Если его использовать в качестве категории, все объекты в блоке получат методы save и load. Для использования категорий Groovy содержит ключевое слово use. Например:

use( PersistenceCategory ) {
	someObject.load(); // Вызывается PersistenceCategory.save( someObject );
	...
	someObject.save(); // PersistenceCategory.load( someObject );
}

Также, на схожие темы

 Подписаться на RSS

 #  #  #  #  #  #  #  #  #  #

Добавить комментарий