Understanding the Observer Pattern

Recently I was asked to integrate third-party forum software into an existing web portal. The problem was, both applications had their own separate authentication mechanism. From a user perspective it would be ideal for users to log in to the portal without having to log in to the forum separately. And in this case, I didn’t want to modify the forum code unnecessarily since it would create a maintenance nightmare – I’d have to merge any subsequent updates and bug fixes from the vendor and be careful not to overwrite my own modifications. This is where the Observer Pattern came in handy for me.

In this article I’ll show you how to implement the Observer Pattern. You’ll learn how various classes in the pattern relate to one another as subject and observers, how the subject notifies observers of a change in its state, and how to identify scenarios where it would be suitable to use the Observer Pattern in your own code.

The Observer Pattern

The Observer Pattern (also known as Publish-Subscribe Pattern) is a behavioral design pattern which defines a one-to-many relationship between objects such that, when one object changes its state, all dependent objects are notified and updated automatically. In my case, I used this pattern to link the portal’s authentication mechanism with the forum software. The act of logging into the portal also automatically triggered the user to be logged into the forum as well.

An object with a one-to-many relationship with other objects who are interested in its state is called the subject or publisher. Its dependent objects are called observers or subscribers. The observers are notified whenever the state of the subject changes and can act accordingly. The subject can have any number of dependent observers which it notifies, and any number of observers can subscribe to the subject to receive such notifications.

The Observer Class

The Observer class provides an update() method which will be called by the subject to notify it of the subject’s state change. In this example, I’ve defined the update() method as a concrete method. If you like, you can define the method here as abstract and then provide a concrete implementation for it in your observer’s subclass.

<?php
abstract class Observer
{
    public function __construct($subject = null) {
        if (is_object($subject) && $subject instanceof Subject) {
            $subject->attach($this);
        }
    }

    public function update($subject) {
        // looks for an observer method with the state name
        if (method_exists($this, $subject->getState())) {
            call_user_func_array(array($this, $subject->getState()), array($subject));
        }
    }
}

The __construct() method accepts an instance of an observable subject and attaches itself to the subject – which I’ll get to momentarily. The update() method retrieves the subject’s current state and uses it to call a subclassed observer method with the same name as the state.

So, in my particular case, I needed to make the portal’s existing Auth class an observable subject and create a concrete observer subclass to hook into the forum’s authentication code. My subclass also needed to implement methods using the subject’s states.

The Subject Class

The Subject class is also an abstract class and defines four primary methods: attach(), detach(), setState(), and notify(). For convenience, I’ve also added getState() and getObservers() methods here.

<?php
abstract class Subject
{
    protected $observers;
    protected $state;

    public function __construct() {
        $this->observers = array();
        $this->state = null;
    }

    public function attach(Observer $observer) {
        $i = array_search($observer, $this->observers);
        if ($i === false) {
            $this->observers[] = $observer;
        }
    }

    public function detach(Observer $observer) {
        if (!empty($this->observers)) {
            $i = array_search($observer, $this->observers);
            if ($i !== false) {
                unset($this->observers[$i]);
            }
        }
    }

    public function getState() {
        return $this->state;
    }

    public function setState($state) {
        $this->state = $state;
        $this->notify();
    }

    public function notify() {
        if (!empty($this->observers)) {
            foreach ($this->observers as $observer) {
                $observer->update($this);
            }
        }
    }


    public function getObservers() {
        return $this->observers;
    }
}

The attach() method subscribes an observer to the subject so that any changes in state can be conveyed to it. The detach() method unsubscribes the observer from the subject, so that it no longer observes the subject for state changes.

The setState() method sets the subject’s current state and calls notify() to update the observers, i.e. publishes notifications to each observer. The notify() method in turn updates each of the subscribed objects by iterating through the internal list and calling each member’s update() method.

The getState() and getObservers() methods are simply helper functions to return the current subject’s state and list of observers.

Observe Closely… Bringing it Together

Now with abstract base classes for both an observer and subject, I was able to integrate the forum software into the existing web portal. I needed to make the portal’s Auth class an observable subject and set its observable state when the user logs in or out of the portal.

<?php
class Auth extends Subject
{
    function login() {
        // existing code to perform login authentication
        // ...

        // signal any observers that the user has logged in
        $this->setState("login");
    }

    function logout() {
        // existing code to perform some operation when user logs out
        // e.g. destroy session, etc...

        // signal any observers that the user has logged out
        $this->setState("logout");
    }
}

I extended the Subject class so that Auth is observable, and then added a call to setState() in both the login() and logout() methods.

To subclass the Observer, I created an Auth_ForumHook class which was responsible for calling the forum’s API login and logout functions.

<?php
class Auth_ForumHook extends Observer
{
    function login($subject) {
        // call the forum's API functions to log the user in
        // ...
    }

    function logout($subject) {
        // call the forum's API functions to log the user out
        // ...
    }
}

Elsewhere in the code base, where the portal’s Auth class was being instantiated, I attached an Auth_ForumHook, instance to it so that the observer would be notified of any state changes in Auth.

<?php
$auth = new Auth();
// attach an observer
$auth->attach(new Auth_ForumHook());
...

That was the extent of my extra coding requirements – apart from preparing the abstract Observer and Subject classes. Any change in state triggered by Auth‘s login() and logout() methods notified the Auth_ForumHook observer and automatically logged the user in or out of the forum.

To add new observers, say, a login tracker to record when a user logs in or out of the portal, one would just have to provide a concrete Observer class and attach it to the Auth subject without the need to further modify the existing Auth object’s login() and logout() methods.

Summary

The Observer Pattern is an appropriate design pattern to apply in any situation where you have several objects which are dependent on another object and are required to perform an action when the state of that object changes, or an object needs to notify others without knowing who they are or how many there are.

In this article, I have shown you the basic Subject-Observer pattern and provided concrete examples of how you can use this behavioral pattern to easily extend the functionality of an existing class without tightly coupling any new requirements. This pattern enables you to achieve a higher level of consistency between related and dependent objects without sacrificing code re-usability.

Image via JPF / Shutterstock

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Dejan

    This is simply great.
    Please, give us more, especially some real world examples of other patterns

  • Jeremy Cook

    Thanks for the interesting article! Just out of curiosity why didn’t you implement the SplObserver and SplSubject interfaces?

  • http://digitale-avantgarde.com chp

    Nice tutorial.
    In my personal opinion, there should not be an abstract class for the observer, but an interface with the update() Methor. It’s because of general good design rules (program against an interface not against a concrete implementation) and to give classes the option to observe if they already extending another class.

  • http://www.pawelkalisz.pl pkalisz

    Nice one :), hope to see some more useful design patterns tutorials. It is sad that most programmers don’t use them, thinking that they are useless and not realizing how handful design patterns are in every day programming.

  • http://www.cpaneldirectory.com Cpanel Hosting Directory

    Nice tutorial – it would be nicer though if you used PHP5′s SPL intefaces (SplObserver + SplSubject) :)

  • http://yetanotherprogrammingblog.com James

    A very well-written article and a really clear explanation of the Observer pattern.

    I’m just wondering, though, if its the best example of using the Observer pattern? Unless you have multiple observers (like, for example, if you were definitely planning to add the login tracker that you mentioned near the end), is the additional complexity really necessary? After all, every additional line of code that gets written is an additional line of code that needs to be maintained. I wonder if there is a better example of applying this pattern in web apps? (TBH I can’t think of one myself).

    Keep up the good work!

  • dkanen

    In PHP I usually use the Observer pattern with objects that hold business logic. For example a phone object might hold a bunch of button objects that represent the available lines on the phone. When the button is added to the phone, the phone subscribes to it. Then when one of these buttons is updated while the application is processing a request it notifies the phone of the state change. Then the phone checks with the button to see if any state information that it cares about has changed. This helps to prevent the phone from having to know the implementation details of the button.

    Another more general use is in MVC you can have the Model notify a View a state change has occurred. Then the View asks the Model about what changed.

  • http://objectic.cc/ Niko Kivelä

    What do you think is the relation to Event-based notification system such as http://components.symfony-project.org/event-dispatcher/ or https://github.com/symfony/symfony/tree/master/src/Symfony/Component/EventDispatcher. It’s basically a Observer pattern, but where observers can subscribe to certain updates only (at will) and events can be parametrized. Is it the same pattern, a variation, or should it be separated to be in its own scope?

    The principle is the same, but instead of having a subject that sends its updated to its attached observers who are waiting for subject’s state to change, we have subscribers listening to dispatcher (aka subject) and events are triggered by 3rd party who wants its event to be broadcasted.

    The great thing about design patterns is the terminology, you share the knowledge with few words and what it’s trying to resolve. That’s why I would like to get some kind of separation between these two similar but different approaches, not to be unintentionally mixed.

    • Joakim Bengtson

      As I se it the Event-pattern, or Event Driven Development, has at least one advantage over the observer pattern above, when talking about dependencies. In the example above a circular dependency occurs between the Observer class and the Subject class, because the Subject knows of its Observers and the Observer is dependent on certain methods in Subject, and that’s not good. With the event pattern that’s avoided, because the object raising an event is not aware of who’s listening…