Как я могу добавить аналогичную функциональность для ряда методов в Java? - PullRequest
3 голосов
/ 12 июня 2010

У меня есть много методов для ведения журнала, например logSomeAction, logAnotherAction и т. Д.

Теперь я хочу, чтобы все эти методы делали небольшую паузу после печати сообщений (Thread.sleep).

Если бы я делал это вручную, я бы сделал что-то вроде этого:

//before:
public static void logSomeAction () {
   System.out.println (msg(SOME_ACTION));
}

//after:
public static void logSomeAction () {
   System.out.println (msg(SOME_ACTION));
   try {
      Thread.sleep (2000);
   } catch (InterruptedException ignored) { }
}

Я помню, что в Java есть прокси-классы и некоторые другие магические инструменты. Есть ли способ избежать копирования-n-вставки N блоков сна в N методов ведения журнала?

Ответы [ 6 ]

7 голосов
/ 12 июня 2010

Вы можете использовать Аспекты , чтобы добавить дополнительную «ортогональную» функциональность вашим методам.

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

2 голосов
/ 12 июня 2010

Похоже, вы хотите использовать Аспектно-ориентированное программирование.Вы можете использовать Spring для AOP или AspectJ.

1 голос
/ 12 июня 2010

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

public interface SomeActionLogger
{
   void logSomeAction();
   void logSomeOtherAction();
   // etc..
}

Затем вы создаете конкретную реализацию

public class SystemOutActionLogger implements SomeActionLogger
{
   public void logSomeAction () {
      System.out.println (msg(SOME_ACTION));
   }
}

После этого прокси Java могут обернуть интерфейс SomeActionLogger

class DelayAfterInvocationHandler implements InvocationHandler
{
    private Object delegate;
    private int duration;

    DelayAfterInvocationHandler(Object delegate, int duration)
    {
        this.delegate = delegate;
        this.duration = duration;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    {
        Object returnValue = method.invoke(delegate, args);
        Thread.sleep(duration);
        // you may want to catch InterruptedEception
        return returnValue;
    }
}

Чтобы скрыть некоторые не очень красивые прокси-коды, у вас может быть метод, который оборачивает ваш регистратор для создания задержки, например

public ActionLogger addDelay(SomeActionLogger logger, int delay)
{
    return (ActionLogger)Proxy.newProxyInstance(
       impl.getClass().getClassLoader(),
       new Class[] { SomeActionLogger.class }, 
       new DelayAfterInvocationHandler(logger, delay));
}

Итак, вы пишете

SomeActionLogger log = addDelay(new SystemOutActionLogger(), 2000);

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

public <T> T addDelay(T delegate, int delay, Class<T> interfaceType)
{
    return (T)Proxy.newProxyInstance(
       delegate.getClass().getClassLoader(),
       new Class[] { type }, 
       new DelayAfterInvocationHandler(delegate, delay));
}
0 голосов
/ 12 июня 2010

Замените все ваши logSomeAction() методы одним logAction(Action a) методом.Таким образом, когда вы добавите больше действий в будущем, вы не будете повторять свой код для обработки журнала действий и спящего потока.

0 голосов
/ 12 июня 2010

Заменить все System.out.println (msg (SOME_ACTION)); с printAndWait (SOME_ACTION); Вы должны быть в состоянии сделать это с помощью поиска и замены. Затем создайте метод

public static void printAndWait(Object someAction) {
   System.out.println (msg(someAction)); 
   try { 
      Thread.sleep (2000); 
   } catch (InterruptedException ignored) {
      Thread.currentThread.interrupt();
   } 
} 

Таким образом, код появляется один раз, и вы можете легко изменить его в одном месте.

0 голосов
/ 12 июня 2010

Создайте служебный класс, который имеет статический метод SleepFor, который включает в себя ваш блок try ... catch, и вызывайте его из каждого метода, в котором вы хотите спать?

...