DEV Community

Binoy Vijayan
Binoy Vijayan

Posted on • Updated on

GoF-Observer Pattern

The Observer pattern is a behavioural design pattern that defines a one-to-many dependency between objects so that when one object (the subject or publisher) changes its state, all its dependents (observers or subscribers) are notified and updated automatically. This pattern is widely used in software systems where changes to one object require dependent objects to be notified and updated accordingly.

Structure:

Subject (or Observable): Maintains a list of observers and provides methods to register, unregister, and notify observers of changes.

Observer (or Subscriber): Defines an interface with a method that the subject calls to notify observers of changes.

Concrete Subject: Implements the subject interface and maintains the state of interest. It notifies observers when its state changes.

Concrete Observer: Implements the observer interface and defines the actions to be taken in response to notifications from the subject.

Explanation:

The Subject maintains a list of observers and provides methods for adding, removing, and notifying observers. It typically contains the state that other objects are interested in.

The Observer defines an interface with a method (e.g., update) that the subject calls to notify observers of changes. It provides a way for observers to receive updates from the subject.

Concrete Subject classes implement the subject interface and manage the state of interest. They notify observers when their state changes by calling the update method on each observer.

Concrete Observer classes implement the observer interface and define the actions to be taken in response to notifications from the subject. They register themselves with the subject to receive notifications.

Example:

Consider a weather monitoring system where multiple displays need to be updated whenever the weather conditions change. We can use the Observer pattern to implement this system:

// Subject (Observable)
protocol WeatherSubject {
    func register(observer: WeatherObserver)
    func remove(observer: WeatherObserver)
    func notify()
}

// Observer (Subscriber)
protocol WeatherObserver {
    func update(temperature: Double, humidity: Double, pressure: Double)
}

// Concrete Subject
class WeatherStation: WeatherSubject {
    private var observers = [WeatherObserver]()
    private var temperature: Double = 0
    private var humidity: Double = 0
    private var pressure: Double = 0

    func register(observer: WeatherObserver) {
        observers.append(observer)
    }

    func remove(observer: WeatherObserver) {
        if let index = observers.firstIndex(where: { $0 === observer }) {
            observers.remove(at: index)
        }
    }

    func notify() {
        for observer in observers {
            observer.update(temperature: temperature, humidity: humidity, pressure: pressure)
        }
    }

    func setMeasurements(temperature: Double, humidity: Double, pressure: Double) {
        self.temperature = temperature
        self.humidity = humidity
        self.pressure = pressure
        notify()
    }
}

// Concrete Observer
class Display: WeatherObserver {
    func update(temperature: Double, humidity: Double, pressure: Double) {
        print("Temperature: \(temperature), Humidity: \(humidity), Pressure: \(pressure)")
    }
}

// Example usage
let weatherStation = WeatherStation()
let display1 = Display()
let display2 = Display()

weatherStation.register(observer: display1)
weatherStation.register(observer: display2)

weatherStation.setMeasurements(temperature: 25.0, humidity: 60.0, pressure: 1013.25)

Enter fullscreen mode Exit fullscreen mode

In this example:

The WeatherStation class acts as the subject and maintains a list of observers. It provides methods to register, remove, and notify observers.

The Display class acts as the observer and implements the update method to receive updates from the weather station.

When the weather station's measurements change, it calls the notify method to notify all registered observers, which in turn call the update method to update their displays with the new measurements.

This example demonstrates how the Observer pattern allows multiple observers to receive updates from a subject without tight coupling between them. It enables a loosely coupled communication mechanism between objects, promoting modularity and flexibility in software design.

Image description

Usage

The Observer pattern is commonly used in various software systems and scenarios where there is a need for communication and synchronisation between objects.

Here are some common usage examples:

User Interface (UI) Development: In graphical user interface (GUI) frameworks, such as iOS or Android development, the Observer pattern is used to notify UI components (observers) of changes in underlying data models (subjects). For example, an observable data model representing a list of items can notify registered UI components to update their views when the list changes.

Event Handling: In event-driven programming, the Observer pattern is used to handle events and notifications. For instance, in web development, JavaScript frameworks like React or Angular use the Observer pattern to manage state changes and trigger re-rendering of components.

Distributed Systems: In distributed systems, such as message queuing systems or publish-subscribe messaging systems, the Observer pattern is used to implement communication between different components or services. Subscribers (observers) subscribe to topics or channels (subjects) to receive messages or updates.

Model-View-Controller (MVC) Architecture: In MVC architectural patterns, the Observer pattern is used to synchronise the model (data) with the view (presentation). Changes in the model are observed by the view, which then updates its presentation accordingly. This allows for separation of concerns and facilitates modular development.

Data Binding: In frameworks that support data binding, such as AngularJS or Knockout.js, the Observer pattern is used to establish bindings between data models and UI elements. Changes to the data model automatically propagate to the UI, and vice versa, without explicit synchronisation code.

Publish-Subscribe Systems: In systems where publishers publish events or messages, and subscribers consume or react to those events, the Observer pattern is used to implement the publish-subscribe mechanism. Subscribers subscribe to specific topics or channels, and publishers notify subscribers of relevant events.

Logging and Monitoring: In logging and monitoring systems, the Observer pattern is used to monitor changes or events in the system and notify interested parties (observers) for analysis or action. For example, monitoring system performance metrics and alerting administrators of anomalies.

GUI Components and Widgets: In desktop or web applications, GUI components or widgets often use the Observer pattern to react to user interactions or changes in state. For instance, a button component can observe clicks and notify registered event handlers.

Summary

Overall, the Observer pattern is a fundamental design pattern used in various software systems to establish communication and synchronisation between objects in a loosely coupled manner. It promotes modularity, flexibility, and maintainability by decoupling observers from subjects, allowing for easier extension and modification of the system.

Overview of GoF Design Patterns

Top comments (0)