Observer Design Pattern in PHP

1. Definition

The Observer Design Pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

2. Problem Statement

Imagine you're building a weather application. Every time there's a change in the weather data, you want multiple display elements (like current temperature, forecast, statistics) to be updated automatically. Implementing this without a systematic approach can result in messy code with a lot of interdependencies.

3. Solution

The Observer pattern solves this by introducing a subject (the entity being observed) and observers (entities that observe the subject). When the state of the subject changes, all registered observers are notified.

4. Real-World Use Cases

1. News subscription where subscribers get notified when a new article is published.

2. Event management systems trigger specific actions on certain events.

3. Stock market applications notifying investors when specific stock prices change.

5. Implementation Steps

1. Define an Observer interface with an update method.

2. Define a Subject interface with methods to attach, detach, and notify observers.

3. Implement concrete classes for both interfaces.

4. Use the concrete subject to update and notify observers.

6. Implementation in PHP

<?php
// Observer interface
interface Observer {
    public function update($temperature, $humidity, $pressure);
}
// Subject interface
interface Subject {
    public function registerObserver(Observer $observer);
    public function removeObserver(Observer $observer);
    public function notifyObservers();
}
// Concrete Subject
class WeatherData implements Subject {
    private $observers = [];
    private $temperature;
    private $humidity;
    private $pressure;
    public function registerObserver(Observer $observer) {
        $this->observers[] = $observer;
    }
    public function removeObserver(Observer $observer) {
        $key = array_search($observer, $this->observers);
        if($key !== false) {
            unset($this->observers[$key]);
        }
    }
    public function notifyObservers() {
        foreach ($this->observers as $observer) {
            $observer->update($this->temperature, $this->humidity, $this->pressure);
        }
    }
    public function measurementsChanged() {
        $this->notifyObservers();
    }
    public function setMeasurements($temperature, $humidity, $pressure) {
        $this->temperature = $temperature;
        $this->humidity = $humidity;
        $this->pressure = $pressure;
        $this->measurementsChanged();
    }
}
// Concrete Observer
class CurrentConditionsDisplay implements Observer {
    private $temperature;
    private $humidity;
    private $pressure;
    public function update($temperature, $humidity, $pressure) {
        $this->temperature = $temperature;
        $this->humidity = $humidity;
        $this->pressure = $pressure;
        $this->display();
    }
    public function display() {
        echo "Current conditions: {$this->temperature}°C and {$this->humidity}% humidity\n";
    }
}
// Client Code
$weatherData = new WeatherData();
$currentDisplay = new CurrentConditionsDisplay();
$weatherData->registerObserver($currentDisplay);
$weatherData->setMeasurements(25, 65, 1012);
?>

Output:

Current conditions: 25°C and 65% humidity

Explanation:

1. Observer interface defines a method update that is called to update the observer.

2. Subject interface has methods to add, remove, and notify observers.

3. WeatherData is our concrete subject that keeps track of the weather information and notifies observers when the data changes.

4. CurrentConditionsDisplay is a concrete observer that displays the current conditions. When it receives an update, it refreshes its display.

5. In the client code, we create a subject, register an observer, and simulate a change in weather data. This change triggers the observer's update method.

7. When to use?

Use the Observer pattern when:

1. An object's change in state requires the state of other dependent objects to be updated.

2. The core object doesn't know about the exact classes of the dependent objects.

3. You want to build in a broadcast-type communication where changes in one object can notify many other objects, without them being tightly coupled.


Comments