Java-геттеры:Всегда выполнять определенный метод

StackOverflow https://stackoverflow.com/questions/1133851

  •  16-09-2019
  •  | 
  •  

Вопрос

Есть ли способ определить метод, который вызывается каждый раз, когда я вызываю 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, и вам понадобится другое поведение, но идея есть.

Я бы сказал, проксируйте объект для вызова нужного метода.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top