Статьи

Шаблон проектирования наблюдателя на Java

В этом уроке мы поговорим о шаблоне проектирования Observer.

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

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

С этим, давайте углубимся в концепции.

Представление UML:

Мы можем представить шаблон проектирования наблюдателя с помощью следующего UML:

Где мы имеем:

  • Тема: ведет список наблюдателей, предоставляет методы для регистрации / отмены регистрации наблюдателей. Также имеется метод notifyAll () для уведомления всех зарегистрированных наблюдателей о любых изменениях состояния.
  • SubjectImpl: класс, расширяющий функциональность класса Subject , он содержит объект состояния, представляющий его текущее состояние. Обратите внимание, что это хорошая идея иметь неизменный объект состояния, чтобы предотвратить любые непреднамеренные обновления со стороны наблюдателя
  • Наблюдатель: это интерфейс с методом update (), который вызывается Субъектом для уведомления наблюдателя о любых изменениях в его текущем состоянии.
  • ConcreteObserver: это классы, реализующие интерфейс Observer , объекты-наблюдатели регистрируются для прослушивания Subject.

Пример подписки на блог:

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

Для этого мы сначала определим наш класс Subject :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
public abstract class Subject {
     
    private List<Observer> observers = new ArrayList<>();
     
    public void register(Observer observer) {
        this.observers.add(observer);
    }
     
    public void unregister(Observer observer) {
        if(this.observers.contains(observer)) {
            this.observers.remove(observer);
        }
    }
  
    public void notifyAll() {
        for(Observer o : observers) {
            o.update();
        }
    }
}

Причина, по которой мы пометили класс Subject как абстрактный, заключается в том, что мы хотим, чтобы Subject имел хотя бы какое-то состояние.

Теперь, когда мы реализовали наш суперкласс Subject , давайте напишем наш класс Blog :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
public class Blog extends Subject {
  
    private String title;
    private String author;
     
    public Blog(String title, String author) {
        this.title = title;
        this.author = author;
    }
  
    public void publish(Post post) {
        //code to publish a new post
         ...
        notifyAll();  
    }
  
    public Post getRecentPost() { ... }
  
    ...
}

Наш класс Blog расширяется от Subject и вызывает метод notifyAll () внутри метода post (), чтобы уведомить всех подписчиков, как только статья будет опубликована.

Реализация Обозревателя:

Давайте теперь определим наш интерфейс Observer и класс Subscriber :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public interface Observer {
  
    void update();
}
  
public class Subscriber implements Observer {
  
    private String name;
    private Subject subject;
  
    public Subscriber(String name) {
        this.name = name;
    }
     
    public void subscribeTo(Subject subject) {
        subject.register(this);
        this.subject = subject;
    }
     
    public void unsubscribeFrom(Subject subject) {
        subject.unregister(this);
        this.subject = null;
    }
  
    @Override
    public void update() {
        if(this.subject == null) {
            System.out.println("Not yet subscribed!");
            return;
        }
        //get the last published post
        Post recentPost = this.subject.getRecentPost();
        System.out.println(this.name + ", a new post got published: " + recentPost);
    }  
}

Обратите внимание, что подписчик блога будет использовать метод subscribeTo () для подписки на блог. Как только пользователь подписывается на блог, он / она автоматически получит обновление всех новых опубликованных сообщений.

Тестирование нашей реализации:

Давайте быстро протестируем наш код:

01
02
03
04
05
06
07
08
09
10
11
12
//in the main method
Subject programmerGirlBlog = new Blog("ProgrammerGirl", "Shubhra");
  
Observer james = new Subscriber("James");
Observer selena = new Subscriber("Selena");
  
james.subscribeTo(programmerGirlBlog);
selena.subscribeTo(programmerGirlBlog);
  
Post compositeDesignPattern = new Post("Composite Design Pattern");
  
programmerGirlBlog.publish(compositeDesignPattern);

Выполнив приведенный выше код, мы получим что-то вроде:

1
2
James, a new post got published: Composite Design Pattern ...
Selena, a new post got published: Composite Design Pattern ...

Вывод:

В этом кратком руководстве мы научились реализовывать шаблон проектирования Observer. Этот шаблон проектирования используется для реализации модели JMS издатель-подписчик. Кроме того, классы, такие как java.util.EventListener и javax.servlet.http.HttpSessionAttributeListener, используют этот шаблон.

Кроме того, полезно знать, что Java предоставляет базовые реализации для наблюдателя и предметных классов, названных соответственно java.util.Observer и java.util.Observable .

Опубликовано на Java Code Geeks с разрешения Шубхры Шриваставы, партнера нашей программы JCG . См. Оригинальную статью здесь: Шаблон проектирования Observer в Java

Мнения, высказанные участниками Java Code Geeks, являются их собственными.