Загрузка...
Загрузка...
Наблюдатель (Observer) — это поведенческий паттерн проектирования, который позволяет объектам подписываться на события, происходящие в другом объекте, и автоматически получать уведомления об изменениях его состояния. Объект, отправляющий сообщения, называется издателем (subject), а объекты, подписывающиеся на его уведомления, — наблюдателями (observers).
Идея паттерна:
«Наблюдатель» упрощает координацию и поддержание согласованности между несколькими объектами, позволяя одному объекту (Subject) уведомлять других (Observers) о своих изменениях без жёсткой привязки к их реализации.
Когда один объект должен сообщать другим о своих изменениях, но не должен знать детали их реализации (принцип низкой связанности).
Когда есть несколько зависимых объектов (наблюдателей), которые должны реагировать на изменения в одном объекте (издателе).
Когда количество наблюдателей не фиксировано на этапе компиляции, и должно меняться «на лету».
Интерфейс издателя (Subject)
Описывает методы для подписки (attach) и отписки (detach) наблюдателей, а также для уведомления (notify).
Интерфейс наблюдателя (Observer)
Содержит метод update(), который вызывается издателем.
Конкретный издатель (Concrete Subject)
Хранит состояние, которое могут отслеживать наблюдатели, и реализует методы подписки/отписки. При изменении состояния вызывает notify().
Конкретный наблюдатель (Concrete Observer)
Реагирует на уведомления, получая нужные данные от издателя.
// 1. Интерфейс наблюдателя
interface Observer {
update(subject: Subject): void;
}
// 2. Интерфейс издателя
interface Subject {
attach(observer: Observer): void;
detach(observer: Observer): void;
notify(): void;
}
// 3. Конкретный издатель
class ConcreteSubject implements Subject {
private observers: Observer[] = [];
private state: number = 0;
public attach(observer: Observer): void {
this.observers.push(observer);
}
public detach(observer: Observer): void {
const index = this.observers.indexOf(observer);
if (index !== -1) {
this.observers.splice(index, 1);
}
}
public notify(): void {
for (const observer of this.observers) {
observer.update(this);
}
}
// Пример изменения состояния
public setState(value: number) {
this.state = value;
console.log(`Subject: состояние изменилось на ${this.state}`);
this.notify();
}
public getState(): number {
return this.state;
}
}
// 4. Конкретный наблюдатель
class ConcreteObserverA implements Observer {
public update(subject: Subject): void {
if (subject instanceof ConcreteSubject && subject.getState() < 5) {
console.log("ConcreteObserverA реагирует, так как состояние < 5");
}
}
}
class ConcreteObserverB implements Observer {
public update(subject: Subject): void {
if (subject instanceof ConcreteSubject && subject.getState() >= 5) {
console.log("ConcreteObserverB реагирует, так как состояние >= 5");
}
}
}
// Пример использования
function clientCode() {
const subject = new ConcreteSubject();
const observerA = new ConcreteObserverA();
const observerB = new ConcreteObserverB();
subject.attach(observerA);
subject.attach(observerB);
// Изменяем состояние
subject.setState(3);
subject.setState(7);
subject.detach(observerA);
subject.setState(2); // Теперь только observerB отслеживает
}
clientCode();
Важно:
Паттерн «Наблюдатель» может быть потенциально опасен при большом количестве подписчиков или сложных зависимостях. Тщательно отслеживайте, какие события посылаются и куда, чтобы не превратить проект в «спагетти»-код.
Паттерн «Наблюдатель» упрощает реализацию реактивных приложений и снижает связанность между компонентами. Он широко используется во фронтенде (например, в архитектуре Flux/Redux, где подписчики реагируют на изменение состояния магазина). Однако будьте осторожны с потенциальным ростом сложности при большом числе подписчиков и пересекающихся событий.
Подробнее про Observer можно почитать здесь.