Also known as Event-Subscriber, Listener

Observer

Intent

Observer is a behavioral design pattern that lets you define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

Problem

Imagine that you have two objects, a Customer and a Store. The store is about to receive a large shipment of a new product, which is very interesting to some customers.

While customers could visit the store every day to check the availability of product, most of these trips would be pointless while the product is still on the way.

On the other hands, the store could send tons of emails (spam) to all customers each time it receives a new shipment. But this would upset other customers, that do not care about the new product.

Thus, we have a conflict: either customer wastes resources on periodic checks or the store itself wastes resources notifying wrong customers.

Solution

Let's call an object that has some interesting state a Publisher. Let's call another object that wants to track changes to that state a Subscriber.

The Observer pattern provides the publisher with a list of the subscribers, interested in tracking its state. The list can be modified via several subscription methods available to subscribers. Thus, each subscriber is able to add or remove itself from the list whenever it wants.

Now the interesting part. Each time there is an interesting event inside the publisher, it goes over its subscriber list and calls notification method in each of their objects.

Publishers can work with any subscriber since all of them follows the common interface. This interface declares a notification method with a set of parameters, which can be used to supply subscribers with the event details.

If an application has several publisher types, the common publisher interface also can be extracted. It would consist of several subscription methods. The interface would allow subscribers to observe publishers' state without coupling to their concrete classes.

Real-World Analogy

Magazine subscription

Once subscribed to a newspaper or magazine, you no longer need to go to the store and check if a next issue is available. Instead, the publisher will send new issues directly to your mailbox right after the publication.

The publisher maintains a list of subscribers and knows which magazines they are interested in. Subscribers can leave the list at any time when they wish to stop publisher sending new magazine issues to them.

Structure

Observer design pattern
  1. Publisher issues events interesting for other objects. These events occur when the publisher changes its state or when it executes some behaviors. Publishers contain a subscription infrastructure that allows new subscribers to join and old subscribers to leave the list.

    When a new event happens, publisher goes over the list of subscribers and calls their notification method, declared by the Subscriber interface.

  2. Subscriber declares the notification interface. In most cases, it consists of a single update method. The method may have several parameters that allow subscribers receiving some of the event details along the update.

  3. Concrete subscriber implements the notification interface and performs some action in response to the update issued by the Publisher.

    Subscribers usually need more that just a simple method call to properly handle the update. For this reason, publishers often pass some context data as arguments of the notification method. This might even be a reference to the publisher's object itself.

  4. Client creates publisher and subscriber objects separately and then registers subscribers for publisher updates.

    Sometimes it is convenient to have direct access from a subscriber's object to a specific publisher. The link is often established via subscriber's constructor. It allows the subscriber to fetch updated state directly from the publisher object upon receiving a notification.

Pseudocode

In this example, the Observer allows the text editor object to notify other objects about changes in its state. The list of subscribers is compiled dynamically. Objects can both start and stop listening for the updates in the runtime.

In this implementation, the editor does not maintain the list of subscribers by itself but rather delegates this job to a special helper object. This allows other objects to reuse the subscription infrastructure. Thus, the Observer pattern allows dynamic configuration of the handlers for various events that occur inside objects.

Adding new subscribers to the program does not require changes to existing publisher classes, as long as they work with subscribers through a common interface.

// Base publisher class. It should include the subscription management code and
// notification methods.
class EventManager is
    private field listeners: hash map of eventTypes and EventListeners

    method subscribe(eventType, listener) is
        listeners.add(eventType, listener)

    method unsubscribe(eventType, listener) is
        listeners.remove(eventType, listener)

    method notify(eventType, a) is
        foreach listeners.of(eventType) as listener
            listener.update(a)

// Concrete publisher, which contains real business logic interesting for some
// subscribers. We could extend this class from a base publisher, but that is
// not always possible in real life, since a publisher it might already have a
// parent class. In this case, you can patch the subscription logic in with
// composition, just like we did it here.
class Editor is
    private field events: EventManager
    private field file: File

    constructor Editor() is
        events = new EventManager()

    // Business logic methods can notify subscribers about the changes.
    method openFile(filename) is
        this.file = new File(filename)
        events.notify('open', filename)

    method saveFile() is
        file.write()
        events.notify('save', file.name)
    // ...


// Common subscribers interface. By the way, modern programming languages allow
// to simplify this code and use functions as subscribers.
interface EventListener is
    method update(a)

// List of concrete listeners. They react to publisher updates by doing some
// useful work.
class LogOpenListener is
    private field log: File

    constructor LogOpenListener(log_filename) is
        this.log = new File(log_filename)

    method update(filename) is
        log.write("Opened: " + filename)

class EmailNotificationListener is
    private field email: string

    constructor EmailNotificationListener(email) is
        this.email = email

    method update(filename) is
        system.email(email, "Someone has changed the file: " + filename)


// Application can configure publishers and subscribers even in run time.
class Application is
    method config() is
        editor = new TextEditor()
        editor.events.subscribe("open",
            new LogOpenListener("/path/to/log/file.txt"))
        editor.events.subscribe("save",
            new EmailNotificationListener("admin@example.com"))

Applicability

When changes to the state of one object may require changing other objects, but the are unknown beforehand or change dynamically.

For example, you are developing a GUI framework focused on buttons. You want your clients to be able to hook some custom code to your buttons so that it will fire whenever users press the button.

The Observer pattern allows any object that implements the subscriber interface to subscribe for the event notifications in publisher objects.

Some objects should observe the others, but only for a limited time or in specific cases.

The Observer pattern lets publishers maintain dynamic lists of subscribers. All subscribers can join and leave the list whenever they want at runtime.

How to Implement

  1. Differentiate between the core (or independent) functionality and the optional (or dependent) functionality. The former will act as a publisher, and the later will serve as subscribers.

  2. Create the Subscriber interface. In most cases, a single update method is enough.

  3. Create the Publisher interface and describe the operations for starting and terminating subscription in it. Remember that publisher should work with subscribers via their common interface.

    You have to decide where you put the actual subscription list and the implementation of the subscribtion methods. Usually, this code looks the same for all types of publishers. So the obvious place to put it is a base abstract class derived directly from a Publisher interface. But if you are integrating Observer to an existing class hierarchy, it might be more convenient to create a small helper class that will be maintaining the subscription for specific publishers.

  4. Create Concrete Publisher classes. They should send notifications to the whole list of subscribers each time when something important happens inside the object.

  5. Implement update methods in Concrete Subscribers. Most subscribers would need some context data about the event. It can be passed as an argument to the update method. But there is another option. Upon receiving a notification, the subscriber can fetch any data directly from the publisher object. In this case, the publisher must pass itself via the update method. The less flexible option is to link a publisher to the subscriber permanently via the constructor.

  6. The Client code must create all necessary subscribers and register them with proper publishers.

Pros and Cons

  • Publisher is not coupled to concrete subscriber classes.
  • You can subscribe and unsubscribe objects dynamically.
  • Follows the Open/Closed Principle.
  • Subscribers are notified in random order.

Relations with Other Patterns

  • Chain of Responsibility, Command, Mediator and Observer address various ways of connecting senders and receivers of requests:

    • Chain of Responsibility passes a request sequentially along a dynamic chain of potential receivers until one of them handles a request.

    • Command establishes a one-directional connection from senders to receivers.

    • Mediator has senders and receivers reference each other indirectly.

    • Observer passes a request to all concerned receivers at the same time but allows them to subscribe and unsubscribe from receiving further requests dynamically.

  • The difference between Mediator and Observer patterns is often ellusive. In most cases the patterns are competing, but sometimes they can collaborate.

    The main goal of the Mediator pattern is to elimintate mutual dependencies between a set of system components. All components become dependent from a single mediator object instead. On the other hand, the goal of the Observer is to establish dynamic one-way connections between objects, where some objects act as subordinates of others.

    There's a quite popular Mediator implementation that relies on the Observer pattern. The mediator object acts as publisher and all of the collegue components become subscribers. They dynamically subscribe and unsubscribe to the mediator's events. Implemented this way, both patterns may look very similar.

    But the Mediator pattern can be implemented in different way, where all the components are permanently linked to the same mediator object. This implementation won't look as Observer but still be a case of the Mediator pattern.

    Now imagine another program where all the components become publishers and allow dynamic connections with each other. There won't be a central mediator object, but rather distribute system of observers.

Implementations in Different Programming Languages

Java