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

Паттерн проектирования Observer

Паттерн проектирования Observer

Описание Observer

Наблюдатель (англ. Observer) — поведенческий шаблон проектирования. Также известен как «подчинённые» (Dependents).

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

Шаблон «наблюдатель» применяется в тех случаях, когда система обладает следующими свойствами:

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

Примеры реализации

// Observer Pattern in JavaScript
class Subject {
    constructor() {
        this.observers = [];
    }
    
    attach(observer) {
        this.observers.push(observer);
    }
    
    detach(observer) {
        this.observers = this.observers.filter(obs => obs !== observer);
    }
    
    notify(data) {
        this.observers.forEach(observer => observer.update(data));
    }
}

class Observer {
    constructor(name) {
        this.name = name;
    }
    
    update(data) {
        console.log(`${this.name} received: ${data}`);
    }
}

// Usage
const subject = new Subject();
const observer1 = new Observer('Observer 1');
const observer2 = new Observer('Observer 2');

subject.attach(observer1);
subject.attach(observer2);
subject.notify('Hello World!');
// Observer Pattern in C++
#include <iostream>
#include <vector>
#include <memory>

class Observer {
public:
    virtual ~Observer() = default;
    virtual void update(const std::string& data) = 0;
};

class Subject {
private:
    std::vector<std::shared_ptr<Observer>> observers;
    
public:
    void attach(std::shared_ptr<Observer> observer) {
        observers.push_back(observer);
    }
    
    void detach(std::shared_ptr<Observer> observer) {
        observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
    }
    
    void notify(const std::string& data) {
        for (auto& observer : observers) {
            observer->update(data);
        }
    }
};

class ConcreteObserver : public Observer {
private:
    std::string name;
    
public:
    ConcreteObserver(const std::string& name) : name(name) {}
    
    void update(const std::string& data) override {
        std::cout << name << " received: " << data << std::endl;
    }
};
// Observer Pattern in Go
package main

import "fmt"

type Observer interface {
    Update(data string)
}

type Subject struct {
    observers []Observer
}

func (s *Subject) Attach(observer Observer) {
    s.observers = append(s.observers, observer)
}

func (s *Subject) Detach(observer Observer) {
    for i, obs := range s.observers {
        if obs == observer {
            s.observers = append(s.observers[:i], s.observers[i+1:]...)
            break
        }
    }
}

func (s *Subject) Notify(data string) {
    for _, observer := range s.observers {
        observer.Update(data)
    }
}

type ConcreteObserver struct {
    name string
}

func (o *ConcreteObserver) Update(data string) {
    fmt.Printf("%s received: %s\n", o.name, data)
}

// Usage
func main() {
    subject := &Subject{}
    observer1 := &ConcreteObserver{"Observer 1"}
    observer2 := &ConcreteObserver{"Observer 2"}
    
    subject.Attach(observer1)
    subject.Attach(observer2)
    subject.Notify("Hello World!")
}
# Observer Pattern in Python
from abc import ABC, abstractmethod

class Observer(ABC):
    @abstractmethod
    def update(self, data):
        pass

class Subject:
    def __init__(self):
        self.observers = []
    
    def attach(self, observer):
        self.observers.append(observer)
    
    def detach(self, observer):
        self.observers.remove(observer)
    
    def notify(self, data):
        for observer in self.observers:
            observer.update(data)

class ConcreteObserver(Observer):
    def __init__(self, name):
        self.name = name
    
    def update(self, data):
        print(f"{self.name} received: {data}")

# Usage
if __name__ == "__main__":
    subject = Subject()
    observer1 = ConcreteObserver("Observer 1")
    observer2 = ConcreteObserver("Observer 2")
    
    subject.attach(observer1)
    subject.attach(observer2)
    subject.notify("Hello World!")
<?php
// Observer Pattern in PHP
interface Observer {
    public function update($data);
}

class Subject {
    private $observers = [];
    
    public function attach(Observer $observer) {
        $this->observers[] = $observer;
    }
    
    public function detach(Observer $observer) {
        $key = array_search($observer, $this->observers);
        if ($key !== false) {
            unset($this->observers[$key]);
        }
    }
    
    public function notify($data) {
        foreach ($this->observers as $observer) {
            $observer->update($data);
        }
    }
}

class ConcreteObserver implements Observer {
    private $name;
    
    public function __construct($name) {
        $this->name = $name;
    }
    
    public function update($data) {
        echo $this->name . " received: " . $data . "\n";
    }
}

// Usage
$subject = new Subject();
$observer1 = new ConcreteObserver("Observer 1");
$observer2 = new ConcreteObserver("Observer 2");

$subject->attach($observer1);
$subject->attach($observer2);
$subject->notify("Hello World!");
?>

Источник

Паттерн описан Андреем Болониным.