Menu
Coddy logo textTech

Паттерн Observer

Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy. Урок 68 из 87.

Паттерн Observer — это поведенческий шаблон проектирования, который устанавливает отношение «один ко многим» между объектами. Когда один объект (тематический объект, subject) изменяет состояние, все его зависимые объекты (наблюдатели, observers) автоматически получают уведомление и обновляются. Представьте это как подписку на рассылку: подписчики получают обновления всякий раз, когда публикуется новый контент.

Этот шаблон включает два основных компонента: субъект, который поддерживает список наблюдателей и уведомляет их об изменениях, и наблюдателей, которые определяют метод обновления для ответа на уведомления:

import java.util.ArrayList;
import java.util.List;

interface Observer {
    void update(String message);
}

class NewsPublisher {
    private List<Observer> subscribers = new ArrayList<>();
    
    public void subscribe(Observer observer) {
        subscribers.add(observer);
    }
    
    public void unsubscribe(Observer observer) {
        subscribers.remove(observer);
    }
    
    public void publish(String news) {
        for (Observer subscriber : subscribers) {
            subscriber.update(news);
        }
    }
}

class EmailSubscriber implements Observer {
    private String email;
    
    public EmailSubscriber(String email) {
        this.email = email;
    }
    
    public void update(String message) {
        System.out.println("Email to " + email + ": " + message);
    }
}

Когда издатель выпускает новости, все подписчики уведомляются автоматически:

NewsPublisher publisher = new NewsPublisher();
publisher.subscribe(new EmailSubscriber("alice@mail.com"));
publisher.subscribe(new EmailSubscriber("bob@mail.com"));

publisher.publish("Breaking news!");
// Вывод:
// Email для alice@mail.com: Breaking news!
// Email для bob@mail.com: Breaking news!

Паттерн «Наблюдатель» способствует слабой связанности: субъекту не нужно знать конкретные классы своих наблюдателей — только то, что они реализуют интерфейс Observer. Благодаря этому легко добавлять новые типы наблюдателей, не изменяя субъект.

challenge icon

Задание

Легко

Давайте создадим систему оповещения о ценах на акции с использованием паттерна Observer! Вы создадите систему, в которой тикер акций уведомляет нескольких инвесторов каждый раз, когда цена акции изменяется, позволяя каждому инвестору реагировать на обновления цены по-своему.

Вы организуете код в четырех файлах:

  • Observer.java: Define интерфейс Observer, который будут Implement все инвесторы. Он должен Declare единственный method update(String stockName, double price), который наблюдатели используют для получения уведомлений об изменениях цены.
  • StockTicker.java: Create subject class, который поддерживает list наблюдателей и уведомляет их об изменениях цены. Ваш StockTicker должен иметь:

    Приватное поле типа String для имени акции (задается через constructor).

    Приватное поле типа double для текущей цены (initially 0).

    Приватный list для хранения подписанных наблюдателей.

    Метод subscribe(Observer observer), который добавляет наблюдателя в list.

    Метод unsubscribe(Observer observer), который удаляет наблюдателя из list.

    Метод setPrice(double price), который обновляет цену, а затем уведомляет всех наблюдателей, вызывая их update method с именем акции и новой ценой.

  • Investors.java: Create два разных типа инвесторов, которые Implement интерфейс Observer:

    DayTrader — имеет приватное поле имени, задаваемое через constructor. При обновлении выводит [name] received alert: [stockName] is now $[price] - Making quick trade!

    LongTermInvestor — имеет приватное поле имени, задаваемое через constructor. При обновлении выводит [name] received alert: [stockName] is now $[price] - Holding steady.

    Format цену с двумя десятичными знаками.

  • Main.java: Объедините вашу систему наблюдателей! Вы получите три inputs: название акции (String), первое обновление цены (double) и второе обновление цены (double).

    Create StockTicker с given названием акции. Create DayTrader named "Alice" и LongTermInvestor named "Bob", а затем подпишите обоих на тикер.

    Установите цену в значение первого входного параметра (все наблюдатели получают уведомление). Затем отмените подписку Alice. Наконец, установите цену в значение второго входного параметра (на этот раз уведомление должен получить только Bob).

Вы получите три inputs по порядку: название акции (String), первая цена (double), вторая цена (double).

Это challenge демонстрирует возможности паттерна Observer: StockTicker ничего не знает о конкретных типах инвесторов. Он знает только, что они реализуют Observer. Когда вы отменяете подписку Alice, она перестает получать обновления, а Bob продолжает получать уведомления. Такая слабая связанность упрощает добавление новых типов инвесторов без изменения тикера!

Попробуйте сами

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Прочитать входные данные
        String stockName = scanner.nextLine();
        double firstPrice = scanner.nextDouble();
        double secondPrice = scanner.nextDouble();
        
        // TODO: Создать StockTicker с заданным названием акции
        
        // TODO: Создать DayTrader с именем "Alice"
        
        // TODO: Создать LongTermInvestor с именем "Bob"
        
        // TODO: Подписать Alice и Bob на ticker
        
        // TODO: Установить цену равной firstPrice (оба наблюдателя получают уведомление)
        
        // TODO: Отписать Alice
        
        // TODO: Установить цену равной secondPrice (уведомление получает только Bob)
        
        scanner.close();
    }
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Java