Java-геттеры:Всегда выполнять определенный метод
Вопрос
Есть ли способ определить метод, который вызывается каждый раз, когда я вызываю get?
У меня есть контакт с объектом, и я не хочу устанавливать updateLastUsed();примерно за 30 геттеров для моих участников.
Решение
Я бы предложил АОП, но если мы говорим о J2ME, вам, скорее всего, лучше вручную вставить «onGetCalled()» в каждый из 30 методов доступа, а затем закодировать все, что вам нужно, в этом методе.Возможно, вы захотите передать имя вызываемого метода (или свойства, к которому осуществляется доступ) на случай, если оно понадобится вам в будущем.
Другие советы
Вместо доступа к методу получения ваших свойств вы можете создать один общий метод получения, который принимает имя свойства в качестве входных данных.Тип возвращаемого значения должен быть Object, если ваши свойства имеют разные типы.
В этом общем методе получения вы вызываете метод получения свойства и метод updateLastUsed().В целях безопасности сделайте всех, кто приобретает собственность, частными.
Вы можете добавить вызов каждого метода (скучно) или использовать какую-либо форму АОП (например,AspectJ, ниже для примера) для сопоставления геттеров типа и вызова метода updateLastUsed().
Редактировать:Несколько человек отметили, что 30 геттеров — это запах кода, а вызов другого метода — побочный эффект.первое утверждение является справедливым показателем, но не правилом.Может быть много причин для использования такого типа, без дополнительной информации я бы оставил это в качестве совета, чтобы проверить, можете ли вы разделить обязанности на два или более типа.
Другой момент, касающийся побочных эффектов, может иметь, а может и не иметь значения.Существует множество сквозных проблем, которые имеет смысл применить к методам получения.Например, ведение журнала, аутентификация и кэширование.Пример метода updateLastUsed() может быть частью стратегии кэширования, поэтому безоговорочная критика вопроса, на мой взгляд, незаслуженна.
Пример того, как реализовать pointcut и советы в AspectJ, выглядит следующим образом:
package test;
public aspect TestAspect {
/**
* Match all getters of test.Contact and bind the target.
*/
protected pointcut contactGetters(Contact contact) :
execution(* test.Contact.get*()) && target(contact);
/**
* Before execution of each getter, invoke the updateLastUsed() method
* of the bound target.
*/
before(Contact contact): contactGetters(contact) {
contact.updateLastUsed();
}
}
Для этого потребуется что-то вроде АОП.Я не знаю, насколько хорошо это поддерживается на J2ME, кроме этот.
Помимо АОП, вы можете использовать java.lang.reflect.Proxy
, или манипулирование байт-кодом...
Но не на J2ME
Я рекомендую вызывать updateLastUsed() 30 раз.
Это похоже на работу по аспектно-ориентированному программированию (АОП).
Определение аспекта, который будет выполняться для всего, что начинается с get*
«Новый» материал AspectJ 5 поддерживает использование аннотаций для определения аспектных точек, поэтому вы можете аннотировать свои геттеры для вызова точки. @Before
выполнение тела метода.
Используйте регулярное выражение, чтобы добавить вызов метода к заголовкам метода получения.
Находить:
\w+ get\w+\s*\(\)\s*\{(\s*)
Заменить:
\0updateLastUsed();\1
Эти выражения были протестированы с использованием Eclipse 3.5 (Galileo) с использованием «Заменить все» в диалоговом окне «Найти/Заменить».
Обратите внимание, что используемый вами редактор должен поддерживать многострочное сопоставление (или вам необходимо включить его).В EmEditor 8.05 мне пришлось изменить строку поиска следующим образом:
\w+ get\w+\s*\(\)\s*\{\s*(\n\s*)
так что новая строка сопоставляется явно.Строка замены остается без изменений.
Можно было сделать что-нибудь причудливое, но, честно говоря, именно поэтому в редакторы добавили макросы, чтобы можно было быстро повторить скучный код.
Я бы просто сделал так, чтобы метод вызывался всеми геттерами, а затем использовал макрос для создания вызова (если он должен отличаться по методу).Это все нужно сделать только один раз, а потом вы просто забудете об этом...
Вот способ.Это некрасиво, но вы можете предпочесть это повторению:
public class GetterTest extends TestCase {
private static class Thing {
public int accessCount;
private String name;
private int age;
private <T> T get(T t) {
accessCount++;
return t;
}
public String getName() {
return get(name);
}
public int getAge() {
return get(age);
}
}
public void testGetIncrementsAccessCount() throws Exception {
Thing t = new Thing();
assertEquals(0, t.accessCount);
t.getName();
assertEquals(1, t.accessCount);
t.getAge();
assertEquals(2, t.accessCount);
}
}
Очевидно, что мой get() просто увеличивает accessCount, и вам понадобится другое поведение, но идея есть.
Я бы сказал, проксируйте объект для вызова нужного метода.