Паттерн observer java пример

Java Blog

Паттерн Наблюдатель (Observer) относится к поведенческим (behavioral) паттернам проектирования.

Основная цель данного паттерна это определение зависимости один-ко-многим между объектами, чтобы при изменении состояния объекта, все зависимые от него объекты получали уведомление и обновлялись автоматически.

Используйте паттерн Наблюдатель (Observer) в любой из следующих ситуаций:

  • когда абстракция имеет два аспекта, один зависит от другого. Инкапсуляция этих аспектов в отдельных объектах позволяет варьировать и повторно использовать их независимо.
  • когда изменение одного объекта требует изменения других, и вы не знаете, сколько объектов нужно изменить
  • когда объект должен иметь возможность уведомлять другие объекты, не делая предположений о том, кто эти объекты. Другими словами, вы не хотите, чтобы эти объекты были тесно связаны.

Типичный вариант использования: изменение в одном объекте приводит к изменению в других объектах.

Пример использования паттерна Наблюдатель на Java

Предположим у нас есть чат, все его пользователи должны получать обновления состояния чата. В следующем классе Chat наблюдатели (то есть пользователи чата) хранятся в списке observers. А сообщения чата в списке messages. При получении нового сообщения вызывается функция notifyObservers, отправляющая оповещение всем наблюдателям.

import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; public class Chat < private static final Logger LOGGER = Logger.getLogger(Chat.class.getName()); private Listmessages; private List observers; public Chat() < observers = new ArrayList<>(); messages = new ArrayList<>(); > public void addObserver(ChatObserver observer) < observers.add(observer); >public void removeObserver(ChatObserver observer) < observers.remove(observer); >public void addMessage(String message) < messages.add(message); LOGGER.info(String.format("Chat get new message: %s", message)); notifyObservers(message); >private void notifyObservers(String message) < for (ChatObserver observer : observers) < observer.update(message); >> >

Интерфейс наблюдателя прост — он имеет только 1 метод update для обновления наблюдателя.

public interface ChatObserver

Вот примеры классов реализующих интерфейс ChatObserver и используемых в приложении в качестве пользователей чата.

import java.util.logging.Logger; public class User implements ChatObserver < private static final Logger LOGGER = Logger.getLogger(User.class.getName()); @Override public void update(String message) < LOGGER.info(String.format("%s get new message: %s", this.getClass().getName(), message)); >>
import java.util.logging.Logger; public class Admin implements ChatObserver < private static final Logger LOGGER = Logger.getLogger(Admin.class.getName()); @Override public void update(String message) < LOGGER.info(String.format("%s get new message: %s", this.getClass().getName(), message)); >>

Вот пример приложения чата с пользователями, использующего паттерн Наблюдатель.

Источник

Кофе-брейк #186. Шаблон проектирования Наблюдатель (Observer). Как инициализировать ArrayList в Java

Java-университет

Шаблон проектирования Наблюдатель (Observer) в Java

Кофе-брейк #186. Шаблон проектирования Наблюдатель (Observer). Как инициализировать ArrayList в Java - 1

Источник: Medium Благодаря этому руководству вы ознакомитесь с примером работы шаблона проектирования Наблюдатель (Observer) на языке программирования Java. Шаблон проектирования Наблюдатель (Observer) — это поведенческий паттерн, который позволяет объекту (известному как subject) уведомлять другие объекты (известные как observers, наблюдатели) об изменении своего состояния. Он может быть полезен, если вы хотите синхронизировать несколько объектов, но желаете избежать ручного обновления каждого объекта при изменении состояния субъекта. В Java шаблон проектирования Наблюдатель (Observer) реализован с использованием интерфейса Observer . Он определяет общий интерфейс для всех различных наблюдателей, которые могут быть уведомлены об изменении состояния субъекта. Субъект представлен классом Subject , который поддерживает список наблюдателей и предоставляет методы для присоединения и отсоединения наблюдателей. Вот пример того, как вы можете реализовать шаблон проектирования Observer в Java:

 public interface Observer < public void update(Subject subject); >public class ConcreteObserverA implements Observer < public void update(Subject subject) < // Обновляем наблюдатель A на основе состояния субъекта >> public class ConcreteObserverB implements Observer < public void update(Subject subject) < // Обновляем наблюдатель B на основе состояния субъекта >> public class Subject < private Listobservers = new ArrayList<>(); public void attach(Observer observer) < this.observers.add(observer); >public void detach(Observer observer) < this.observers.remove(observer); >public void notifyObservers() < for (Observer observer : this.observers) < observer.update(this); >> // Другие методы, связанные с состоянием субъекта > 

Чтобы использовать шаблон Наблюдатель (Observer), вы должны сначала создать экземпляры классов Subject и Observer . Затем вы прикрепляете наблюдателя к субъекту, используя на субъекте метод attach . Когда состояние субъекта меняется, вы должны вызвать для субъекта метод notifyObservers , что приведет к обновлению прикрепленных наблюдателей. Далее вы можете отсоединить наблюдателя от субъекта, используя на субъекте метод detach .

Читайте также:  Typescript getters and setters

Как инициализировать ArrayList в Java

Кофе-брейк #186. Шаблон проектирования Наблюдатель (Observer). Как инициализировать ArrayList в Java - 2

Источник: Asyncq В этой статье рассмотрены 8 различных способов инициализации структуры данных ArrayList. Инициализация ArrayList является одним из этапов создания масштабируемого программного обеспечения на языке Java.

Методы инициализации

1. Использование метода Arrays.asList

Пакет java.util , в котором находится класс Arrays , предоставляет различные методы, доступные для работы со структурой данных Array. Одним из наиболее известных среди них является преобразование массива (Array) в список (List) с помощью метода Arrays.asList .

 List countries; countries = Arrays.asList("EUR", "USD", "INR", "JPY"); 

2. Использование анонимного внутреннего класса

 List countries; countries = new ArrayList<>()>; 

3. Общий способ инициализации

Один из распространенных способов, которым многие разработчики инициализируют ArrayList , — это создание объекта ArrayList и последующий вызов метода add .

 List countries; countries = new ArrayList<>(); countries.add("EUR"); countries.add("USD"); countries.add("INR"); countries.add("JPY"); 

4. Использование метода List.of

Java 9+ предоставляет фабричные методы, которые возвращают неизменяемую коллекцию (immutable collection). Чтобы получить неизменяемый список, мы можем использовать метод List.of .

 List countries; countries = List.of("EUR", "USD", "INR", "JPY"); 

5. Инициализация ArrayList из массива

Кроме того, мы можем инициализировать ArrayList из массива, просто передав его как параметр конструктору ArrayList .

 List countries; String[] countryArr = ; countries = Arrays.asList(countryArr); 

6. Инициализация ArrayList потоковым массивом (streaming array)

Если вам нравится lambda и stream, мы можем передать массив с помощью Arrays.stream , а затем собрать данные в List .

 List countries; countries = Arrays.stream(countryArr).collect(Collectors.toList()); 

7. Инициализация ArrayList из Set

Существует также способ инициализации ArrayList из Set . Для этого нам нужно передать его как параметр конструктора в ArrayList .

 List countries; Set set = Set.of("EUR", "USD", "INR", "JPY"); countries = new ArrayList<>(set); 

8. Инициализация ArrayList из стека

Мы можем инициализировать ArrayList из Stack . Для этого нужно передать стек в качестве параметра конструктора в ArrayList .

 List countries; Stack stack = new Stack<>()>; countries = new ArrayList<>(stack); 

Заключение

Сегодня мы рассмотрели различные способы инициализации ArrayList . Как видите, для этого мы можем использовать как традиционные методы, а также новые функции Java. Мой личный фаворит — List.of фабричного метода, чтобы получить неизменяемый список. Но если мне нужен изменяемый список, я бы использовал Arrays.asList .

Читайте также:  Проверка уязвимости кода php

Источник

Шаблон Наблюдатель (Observer)

Java-университет

Как пишет банда четырех (имеется ввиду книга «Паттерны объектно-ориентированного проектирования» 4 первоклассных разработчиков) назначение этого паттерна в том, чтобы определять зависимость типа «один ко многим» между объектами таким образом, что при изменении состояния одного объекта все зависящие от него оповещаются об этом и автоматически обновляются. Еще этот паттерн называют: Dependents (подчиненные) или Publish-Subscribe (издатель — подписчик). Но давайте попробуем разобраться на примере католической церкви 🙂 В ней имеются последователи, верящие в учение данной церкви. При появлении каких-либо новых догматов (обязательных вероучений) и не только — эти люди должны знать о них. Но как же это можно было описать языком программирования, используя данный паттерн? 1. У нас есть «голос церкви» (сама церковь или папа Римский когда вещает ex cathedra), т. е. некий вещатель или субъект, оглашающий новости в церкви. 2. Есть прихожане этой церкви, т. е. некие наблюдатели, которые хотят быть в курсе важных событий. Соответственно сегодня прихожан может быть 1,3 млд человек, а завтра больше или меньше. И оповещать нужно только тех, кто находится в этой церкви (не нужно беспокоить атеистов лишний раз :). Таким образом это все можно было бы выразить следующим образом: Есть церковь, которая будет вещать своей пастве о чем-либо, в которой можно зарегистрироваться или наоборот выйти из нее:

Есть конкретно католическая церковь c реализацией этих методов, а также новостями и списком людей, которым эти новости нужно транслировать:

 public class CatholicChurch implements Church < private Listparishioners; private String newsChurch; public CatholicChurch() < parishioners = new ArrayList<>(); > public void setNewsChurch(String news) < this.newsChurch = news; notifyParishioners(); >@Override public void registerParishioner(Parishioner parishioner) < parishioners.add(parishioner); >@Override public void removeParishioner(Parishioner parishioner) < parishioners.remove(parishioner); >@Override public void notifyParishioners() < for (Parishioner parishioner : parishioners) parishioner.update(newsChurch); >> 

Есть человек-прихожанин, который может войти в лоно церкви или выйти из него (для упрощения кода мы позволим ему только войти 🙂

 public class Parishioner < private String name; public Parishioner(String name, Church church) < this.name = name; church.registerParishioner(this); >void update(String newsChurch) < System.out.println(name + "узнал новость: " + newsChurch); >> 
 Мартин Лютер узнал новость: Инквизиция была ошибкой. месса Mea Culpa 12 марта 2000 года Жан Кальвин узнал новость: Инквизиция была ошибкой. месса Mea Culpa 12 марта 2000 года 

Т.е. как только в церкви появится новость, будут оповещены о ней все, кто находятся в массиве зарегистрированных членов данной церкви. В чем недостатки данной реализации: 1. Во первых интерфейс где можно зарегистрироваться и получать новости может касаться не только данной церкви (возможно такое потребуется). Поэтому можно было бы сразу вынести это в отдельный интерфейс Observable. 2. Так же можно было бы поступить с прихожанами церкви, а именно метод update вынести в отдельный интерфейс и реализовать у нужного прихожанина его. Тогда данный метод смогут использовать вообще и не прихожане католической церкви, а например векующие в существование эльфов (имеется ввиду движение «Дорога к Единорогу»). Т.е. создать интерфейс Observer с методом update. Что в итоге получится:

 public class CatholicChurch implements Observable < private Listparishioners; private String newsChurch; public CatholicChurch() < parishioners = new ArrayList<>(); > public void setNewsChurch(String news) < this.newsChurch = news; notifyObservers(); >@Override public void registerObserver(Observer o) < parishioners.add(o); >@Override public void removeObserver(Observer o) < parishioners.remove(o); >@Override public void notifyObservers() < for (Observer o : parishioners) o.update(newsChurch); >> 
 public class Parishioner implements Observer < private String name; public Parishioner(String name, Observable o) < this.name = name; o.registerObserver(this); >@Override public void update(String news) < System.out.println(name + " узнал новость: " + news); >> 

Таким образом: Мы «ослабили связь» между церковью и прихожанами, что естественно хорошо только в программировании 🙂 Субъект (католическая церковь) имеет лишь список слушателей (прихожан) и при получении новостей (изменений), транслирует данные новости своим слушателям. Можно завести теперь любой другой субъект (например протестанскую церковь) и там уже транслировать новости «своим» слушателям. Также нужно учесть, что данные 2 класса (точнее класс Observable и интерфейс Observer) имелись в пакете java.util java, но сейчас они Deprecation с java 9 (https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Observable.html): Deprecated. This class and the Observer interface have been deprecated. The event model supported by Observer and Observable is quite limited, the order of notifications delivered by Observable is unspecified, and state changes are not in one-for-one correspondence with notifications. For a richer event model, consider using the java.beans package. For reliable and ordered messaging among threads, consider using one of the concurrent data structures in the java.util.concurrent package. For reactive streams style programming, see the Flow API. Поэтому использовать их не нужно. А вместо них можно использовать другие, но суть паттерна от этого не изменится. Для примера давайте попробует использовать PropertyChangeListener (чтобы не писать лишние классы, которые уже написаны) из пакета java.beans. Давайте посмотрим как это будет: класс субъекта:

 public class CatholicChurch < private String news; // используя support мы можем добавлять или удалять наших прихожан (слушателей) private PropertyChangeSupport support; public CatholicChurch() < support = new PropertyChangeSupport(this); >public void addPropertyChangeListener(PropertyChangeListener pcl) < support.addPropertyChangeListener(pcl); >public void removePropertyChangeListener(PropertyChangeListener pcl) < support.removePropertyChangeListener(pcl); >public void setNews(String value) < support.firePropertyChange("news", this.news, value); this.news = value; >> 
 public class Parishioner implements PropertyChangeListener < private String name; public Parishioner(String name) < this.name = name; >public void propertyChange(PropertyChangeEvent evt) < this.setNews((String) evt.getNewValue()); >public void setNews(String news) < System.out.println(name + " узнал новость: " + news); >> 
 public static void main(String[] args)

Мартин Лютер узнал новость: Дева Мария имеет непорочное зачатие. булла Ineffabilis Deus. 8 декабря 1854 года Папа Пий IX Жан Кальвин узнал новость: Дева Мария имеет непорочное зачатие. булла Ineffabilis Deus. 8 декабря 1854 года Папа Пий IX Мартин Лютер узнал новость: Папа непогрешим. не всегда конечно, а только когда транслирует учение церкви ex cathedra. Первый Ватиканский собор 1869 год Жан Кальвин узнал новость: Папа непогрешим. не всегда конечно, а только когда транслирует учение церкви ex cathedra. Первый Ватиканский собор 1869 год

Читайте также:  Платформа для разработки php

Источник

Оцените статью