It is used to establish a one-to-many dependency between objects so that when one object changes its state, all its dependent objects are notified and updated automatically.

Components

SOLID principles

Implementation

Interface Polymorphism

// Observable

interface Observable {
  attach(observer: Observer): void;
  detach(observer: Observer): void;
  notify(): void;
}

class WeatherStation implements Observable {
  private observers: Observer[] = [];
  private temperature: number = 0;
  private humidity: number = 0;

  attach(observer: Observer): void {
    this.observers.push(observer);
  }

  detach(observer: Observer): void {
    this.observers = this.observers.filter(obs => obs !== observer);
  }

  notify(): void {
    for (const observer of this.observers) {
      observer.update(this.temperature, this.humidity);
    }
  }

  setMeasurements(temperature: number, humidity: number): void {
    this.temperature = temperature;
    this.humidity = humidity;
    this.notify();
  }
}

// Observer

interface Observer {
  update(temperature: number, humidity: number): void;
}

class PhoneDisplay implements Observer {
  private id: string;

  constructor(id: string) {
    this.id = id;
  }

  update(temperature: number, humidity: number): void {
    console.log(
      `PhoneDisplay [${this.id}]: Temperature: ${temperature}, Humidity: ${humidity}`
    );
  }
}

Go Interface Polymorphism

// Observable

type Observable interface {
	Attach(observer Observer)
	Detach(observer Observer)
	Notify()
}

func (ws *WeatherStation) Attach(observer Observer) {
	ws.observers = append(ws.observers, observer)
}

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

func (ws *WeatherStation) Notify() {
	for _, observer := range ws.observers {
		observer.Update(ws.temperature, ws.humidity)
	}
}

func (ws *WeatherStation) SetMeasurements(temperature, humidity float64) {
	ws.temperature = temperature
	ws.humidity = humidity
	ws.Notify()
}

// Observer

type Observer interface {
	Update(temperature float64, humidity float64)
}

type PhoneDisplay struct {
	id string
}

func (pd *PhoneDisplay) Update(temperature float64, humidity float64) {
	fmt.Printf("PhoneDisplay [%s]: Temperature: %.2f, Humidity: %.2f\\n", pd.id, temperature, humidity)
}

References