Мы будем наблюдать или паттерн Observer.

Все вы наверное знаете или хотя бы слышали про паттерн Observer. Если нет, то я немного поясню. Это некий аналог событий, только без единого event-loop’а. То есть у нас есть класс который шлет события и есть классы подписчики которые слушают события конкретного класса, а не шину событий.

А знали ли вы, что в Java есть встроенная реализация паттерна Observer? Есть специальный интерфейс для Observer’ов и наблюдаемого класса. Мы их рассмотрим далее в этой статье.

Класс Observable.

Этот конкретный класс, не абстрактный, он имеет в себе методы которые позволяют послать событие наблюдателям.

В этом классе есть некоторые особенности, в частности, тут не как в PHP, здесь чтобы послать событие наблюдателям нужно сначала вызвать метод setChanges() который поставит булевский флаг внутри класса Observable и только потом можно вызвать метод notifyObservers(), есть перегруженная версия метода notifyObservers() которая позволяет послать нам объект - событие. Если перед вызовом notifyObservers() вы не вызвали метод setChanges() то событие не отправится, но и исключения не будет.

Есть еще один особенный метод clearChanged() который в свою очередь “очищает” изменения в классе Observable, это значит что он просто внутри нашего класса Observable ставит флаг false, полная противоположность методу setChanges().

Интерфейс Observer.

Этот интерфейс описывает класс наблюдателя, в нем обозначается единственный метод update. Со следующей сигнатурой.

public void update(Observable o, Object arg)

Здесь первым параметром передается класс который послал событие, а вторым параметром объект события который можно передать в перегруженном методе notifyObservers(), если вызвался не перегруженный вариант метода notifyObservers() то параметр arg будет null’ом.

Реализуем этот паттерн.

Давайте сначала создадим класс события которое мы будем слать к нашим наблюдателям. К примеру это будет класс Message который будет представлять из себя обычный POJO.

class Message {

  private String body;

  public String getBody() {
      return body;
  }

  public void setBody(String body) {
      this.body = body;
  }

  public static Message fromBody(String body) {
      Message message = new Message();
      message.setBody(body);

      return message;
  }
}

Думаю здесь в комментариях никто не нуждается и всем все понятно.

Теперь давайте сделаем класс Observable, он не будет выполнять полезной информации, он будет просто слать событие.

class ObservableClass extends Observable {

  public void main() {
      Message event = Message.fromBody("I'm event :)");

      setChanged();
      notifyObservers(event);
  }
}

Здесь мы заводим void метод main() который посылает событие Message всем своим наблюдателям. Имейте ввиду что классы дочерние от Observable это обычные классы которые ничем не отличаются от других, это значит что вы можете делать какие угодно методы с какими угодно сигнатурами.

Пора завести класс наблюдателя.

class ObserverClass implements Observer {

  private final static Logger logger = Logger.getLogger("OBSERVER");

  @Override
  public void update(Observable o, Object arg) {
      Message event = (Message) arg;

      logger.info(event.getBody());
  }
}

Здесь мы не глядя преобразуем наш Object в Message, но в реальных условиях так делать не нужно, потому что в реальном приложении скорее всего класс наблюдателей будут переиспользоваться.

Паттерн мы реализовали, а как запустить то все это теперь? А запустить все очень просто, давайте же сделаем это.

public class Application {

  public static void main(String[] args) {

      ObservableClass observableClass = new ObservableClass();
      observableClass.addObserver(new ObserverClass());

      observableClass.main();
  }
}

Ну тут все предельно просто, мы создаем наш класс Observable и присоединяем к нему Observer. Observer’ов может быть неограниченное количество, также их можно удалять, есть специальный метод deleteObserver(Observer o), а можете удалить и всех наблюдателей сразу с помощью метода deleteObservers().

Теперь, если вы запустите этот пример, то увидите на консоле текст.

I'm event :)

Давайте теперь проследим весь цикл выполнения данное программы. Мы создали событие которое будет посылаться наблюдателям, мы создали класс который будет посылать события и создали класс который будет ловить эти события, после этого мы создали объект класса ObservableClass и прикрепили к нему наш класс наблюдатель и вызвали метод main который создал событие и передал его всем наблюдателям, наш наблюдатель словил это событие и вывел на консоль.

С помощью этого паттерна можно создавать очень изощренную архитектуру в хорошем смысле этого слова.

На этом все, если остались вопросы, пишите в комментариях, не стесняйтесь.

Java
04.12.2016
1 ответ
авторизуйтесь чтобы ответить