1. Что такое паттерн Наблюдатель

Паттерн Наблюдатель - это поведенческий паттерн проектирования, используемый для установления один-ко-многим зависимостей между объектами. Когда объект (называемый субъектом или наблюдаемым) изменяется, все его зависимости (называемые наблюдателями) уведомляются и обновляются автоматически. Этот паттерн позволяет достичь слабой связанности между субъектами и наблюдателями, обеспечивая тем самым их деклассирование и гибкость.

2. Характеристики и Преимущества паттерна Наблюдатель

Паттерн Наблюдатель обладает следующими характеристиками и преимуществами:

  • Cлабая связь между субъектами и наблюдателями, где субъект не нужно знать конкретные детали реализации наблюдателей.
  • Динамическое добавление и удаление наблюдателей, делая систему более гибкой.
  • Cледует принципу открытости/закрытости между субъектами и наблюдателями, обеспечивая независимое расширение и возможность повторного использования.
  • Cпособен установить один-ко-многим зависимость, где субъект может иметь несколько наблюдателей.

3. Примеры Практического Применения паттерна Наблюдатель

Паттерн Наблюдатель имеет множество практических применений в реальной жизни, таких как:

  • Механизм обработки событий в графических пользовательских интерфейсах, например, обработка действий при нажатии кнопки.
  • Отслеживание реального времени котировок на фондовом рынке.
  • Уведомление о рекламных акциях на электронной коммерции.

4. Реализация паттерна Наблюдатель в Golang

4.1 UML-диаграмма классов

Паттерн Наблюдатель в Golang

4.2 Введение в пример

В этом примере у нас есть субъект (Subject) и два наблюдателя (ObserverA и ObserverB). Субъект может регистрировать, удалять и уведомлять наблюдателей.

4.3 Шаги Реализации

4.3.1 Создание интерфейса субъекта и класса Конкретный Субъект

type Subject interface {
    RegisterObserver(observer Observer)
    RemoveObserver(observer Observer)
    NotifyObservers()
}

type ConcreteSubject struct {
    observers []Observer
}

// Регистрация объекта слушателя
func (subject *ConcreteSubject) RegisterObserver(observer Observer) {
    subject.observers = append(subject.observers, observer)
}

// Удаление объекта слушателя
func (subject *ConcreteSubject) RemoveObserver(observer Observer) {
    for i, obs := range subject.observers {
        if obs == observer {
            subject.observers = append(subject.observers[:i], subject.observers[i+1:]...)
            break
        }
    }
}

// Триггер уведомления о событии
func (subject *ConcreteSubject) NotifyObservers() {
    for _, observer := range subject.observers {
        observer.Update()
    }
}

4.3.2 Создание интерфейса наблюдателя и классов Конкретный Наблюдатель

type Observer interface {
    Update()
}

type ConcreteObserverA struct {}

func (observer *ConcreteObserverA) Update() {
    fmt.Println("Наблюдатель A уведомлен.")
}

type ConcreteObserverB struct {}

func (observer *ConcreteObserverB) Update() {
    fmt.Println("Наблюдатель B уведомлен.")
}

4.4 Демонстрация Кода Примера

func main() {
    subject := &ConcreteSubject{}
    observerA := &ConcreteObserverA{}
    observerB := &ConcreteObserverB{}

    subject.RegisterObserver(observerA)
    subject.RegisterObserver(observerB)

    subject.NotifyObservers()

    subject.RemoveObserver(observerA)

    subject.NotifyObservers()
}

Вывод:

Наблюдатель A уведомлен.
Наблюдатель B уведомлен.
Наблюдатель B уведомлен.

Вышеприведенный пример демонстрирует конкретную реализацию паттерна наблюдателя. Субъект (ConcreteSubject) зарегистрировал двух наблюдателей (ObserverA и ObserverB), затем уведомил этих двух наблюдателей. После этого наблюдатель A был удален из субъекта, и оставшийся наблюдатель B был уведомлен снова.