What are we talking about?

The observer pattern is a (Object Oriented Programming) design pattern in which the subject, or the observable, maintains a list of its dependents, the observers. The observers are automatically notified of any state changes occuring in the subject. This pattern is often used to implement distributed event handling systems.

  1. Traditional use case: A simple application of this pattern occurs commonly in the model-view-controller concept. Your model becomes an observable subject and the view is an observer that is updated when notified of a changed value.

  2. Advantages: useful mostly for dynamic relationships between objects: you can hook up a new observer to an observable while the program is running, then unhook it later.

  3. Drawbacks: The Subject gets decoupled from Observer but you cannot just look at its source code and find out who observes it. Hardcoded dependencies are usually easier to read and think about but they are harder to modify and reuse. It's a tradeoff.

What about a simple example?

#!/usr/bin/env python
# -*- coding:utf-8 -*-

""" Very simple Observer pattern example in Python """

class Subscriber:
    """ The Observer class """

    def __init__(self, name):
        self.name = name

    def update(self, message):
        print('{} received message "{}"'.format(self.name, message))


class Publisher:
    """ The Subject class """

    def __init__(self):
        self.subscribers = set()

    def register(self, subscriber):
        self.subscribers.add(subscriber)

    def unregister(self, subscriber):
        self.subscribers.discard(subscriber)

    def notify(self, message):
        for subscriber in self.subscribers:
            subscriber.update(message)


def main():
    """ main function """

    sub = Publisher()
    observer1 = Subscriber('Observer 1')
    observer2 = Subscriber('Observer 2')

    sub.register(observer1)
    sub.register(observer2)

    sub.notify("Hello")
    sub.unregister(observer2)
    sub.notify("Greetings")

if __name__ == "__main__":
    main()


The output should be:

Observer 1 received message "Hello"
Observer 2 received message "Hello"
Observer 1 received message "Greetings"


Real life people using it?

Yes. From the Django documentation:

[...] In a nutshell, signals allow certain senders to notify a set of receivers that some action has taken place. They’re especially useful when many pieces of code may be interested in the same events. [...]

If we browse the source code, we'll find that an instance of this class will behave as a Subject:

  1. an attribute to store observers:
self.receivers = []


2. a function to register observers:

def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):


3. a function to unregister observers:

def disconnect(self, receiver=None, sender=None, weak=None, dispatch_uid=None):


4. a function to notify observers:

def send(self, sender, **named):


Let's see if we can use the Signal class in a simple Python script:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

""" Observer pattern example using Django signals """

from django.dispatch import Signal
from datetime import datetime

subject = Signal(providing_args=['message'])

def observer1(**kwargs):
    message = kwargs['message']
    print('Observer1, Message: %s\n' % (message))

def observer2(**kwargs):
    message = kwargs['message']
    mydate = "{:%B %d, %Y}".format(datetime.now())
    print('Observer2, Message: %s. Received at %s\n' % (message, mydate))

def main():
    # register observer2
    subject.connect(observer2)

    # notify observers
    subject.send(sender='some_sender', message='Hello!')

    # register observer1
    subject.connect(observer1)

    # notify observers
    subject.send(sender='some_sender', message='Greetings!')

    # unregister observer2
    subject.disconnect(observer2)

    # notify observers
    subject.send(sender='some_sender', message='Howdy!')

if __name__ == "__main__":
    main()


The output should be:

Observer2, Message: Hello!. Received at September 02, 2016

Observer2, Message: Greetings!. Received at September 02, 2016

Observer1, Message: Greetings!

Observer1, Message: Howdy!



Publish-Subscribe pattern, same thing?

It is important to keep in mind that sometimes, the term publisher will be used in place of the term subject. And subscriber in place of observer. But don't get confused, the Publish-Subscribe pattern is something completely different.

The Publish-Subscribe pattern is not related to OOP at all. It's a messaging pattern, a network architecture related pattern.

In this pattern, both the publisher and the subscriber don't know who send or receive the message. Usually involved is a "middle man", such as a message queue who knows all parties, but the individual parties don't know about each other. They just don't need to know that information.

While in the Observer pattern, the subject send messages directly to the observers, and the observers receive the message, directly from the subject.

Observer - Pub/Sub
Image from hsto.org

Going further?

If I find some time, I'll write a whole article on C functions pointers. But before that, I just put it here, a simple implementation of the Observer pattern in C. For those who would be interested:

#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>

// Observable
typedef struct{
  int observer_count;

  // array of function pointers: observers
  void (*observer_list[10])(char *);
} Subject;

// function to initialize our subject with 0 observer
void sub_init(Subject *aSub){
  aSub->observer_count = 0;
}

// function that will unsubscribe an observer to a subject
void disconnect(Subject *aSub, void (*fp)(char *)){
  int i;
  for(i = 0; i < aSub->observer_count; ++i){
    if(aSub->observer_list[i] == fp){
      aSub->observer_count--;
      aSub->observer_list[i] = aSub->observer_list[aSub->observer_count];
    }
  }
}

// function that will subscribe an observer to a subject
void connect(Subject *aSub, void (*fp)(char *)){
  disconnect(aSub, fp);
  aSub->observer_list[aSub->observer_count++] = fp;
}

// function to send message to all observers
void send(Subject *aSub, char *message) {
  int i;
  for( i = 0; i < aSub->observer_count; ++i ) {
    aSub->observer_list[i](message);
  }
}

void observer1(char *message){
  printf( "Observer1. Message received: %s\n", message );
}

void observer2(char *message){
  printf( "Observer2. Message received: %s\n", message );
}


int main() {
  Subject sub;

  sub_init(&sub);
  connect(&sub, observer1);
  connect(&sub, observer2);
  send(&sub, "howdy");

  disconnect(&sub, observer2);
  send(&sub, "greetings");

  return 0;
}


You may find interesting: