Внедрение кода в методы до и после основного блока выполнения - PullRequest
1 голос
/ 02 ноября 2019

У меня есть пара классов, которые реализуют конкретный interface, что-то вроде следующего (это, очевидно, очень упрощенная версия, но суть вопроса):

public interface Talk {
  void sayIt();
}

Первая реализация Talk:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SayHello implements Talk {

  static final Logger LOG = LoggerFactory.getLogger(SayHello.class);

  public SayHello() {}

  public void sayIt() {
    System.out.println("Hello");
  }
}

Вторая реализация Talk:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SayGoodbye implements Talk {

  static final Logger LOG = LoggerFactory.getLogger(SayHello.class);

  public SayGoodbye() {}

  public void sayIt() {
    System.out.println("GoodBye");
  }

}

Теперь в методе sayIt() я хочу реализовать ведение журнала уровня трассировки и некоторые таймеры выполнения метода, которыеЯ могу просто сделать что-то следующим образом:

public void sayIt() {
    long startTime = System.currentTimeMillis();
    LOG.trace("Executing sayIT for implementation {} , start time at {}.", this.getClass().getSimpleName(), startTime);
    System.out.println("Hello");
    LOG.trace("sayIT for implementation {} took {} milliseconds to execute.", this.getClass().getSimpleName(), System.currentTimeMillis() - startTime);
}

Проблема в том, что мне нужно было бы скопировать и вставить это в каждую реализацию метода sayIt() для каждой class, которая реализует Talkинтерфейс, и я действительно не хочу этого делать, потому что ...

  1. Это создает много дублирования.
  2. С большим количеством реализаций вы начинаете испытывать головную боль при обслуживании, особенно когда вырешите немного изменить реализацию.
  3. Я ленивый и хотел бы писать как можно меньше кода, используя как можно больше.

Итак, вот вопрос .... как бы я достиг целиписать один раз, использовать несколько раз? Синхронизация методов - это одно из приложений, но я действительно хочу иметь возможность «вставлять» код в начало и конец метода.

Я действительно ищу рабочий пример (не просто ссылку на дополнительные ссылки) чего-то, что может работать (я предполагаю что-то вроде AspectJ ,но у меня были бесконечные хлопоты, пытаясь заставить его работать с Gradle ... возможно, просто попытался реализовать Maven)

О, да, я мог бы вместо добавления кода в sayIt() добавить его вкод, вызывающий sayIt(), например:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;

public class SomeOtherClass {

  static final Logger LOG = LoggerFactory.getLogger(SomeOtherClass.class);

  public SomeOtherClass() {}

  public void letsHaveAConversation() {
    List<Talk> talks = new ArrayList<>();
    talks.add(new SayHello());
    talks.add(new SayGoodbye());
    for (Talk talking : talks) { 
        long startTime = System.currentTimeMillis();
        LOG.trace("Executing sayIT for implementation {} , start time at {}.", talking.getClass().getSimpleName(), startTime);
        talking.sayIt();
        LOG.trace("sayIT for implementation {} took {} milliseconds to execute.", talking.getClass().getSimpleName(), System.currentTimeMillis() - startTime);
    }
  }

}

Это будет работать, но не в том случае, если у меня несколько мест, откуда вызывается sayIt().

1 Ответ

1 голос
/ 02 ноября 2019

Почему бы просто не обернуть вызов sayIt в общий метод абстрактного класса?

abstract class AbstractTalk implements Talk {
    public void sayIt() {
        trace();
        startMeasure();

        doSayIt();

        stopMeasure();
    }

    abstract protected doSayIt(); // here implement the logic
}
...