Design Pattern Examples
Overview of object-oriented design patterns
Observer Pattern

Diagram of the Observer pattern

The Observer pattern is used when one or more entities need to be told about a change in state of another entity (typically known as the Subject) and those entities, upon notification, pull data from the Subject to complete their own specific tasks. Alternatively, the Subject could push the data to the observing entities.

The Observer pattern uses a publish/subscribe model, where entities interested in changes in the Subject subscribe to the Subject for change notifications. This allows the Subject to notify multiple subscribers (observers) about a single change. It is then up to the observer to do something in response to the change notification.

One common example of the observer pattern is the View element of the Model-View-Controller architecture. In this architecture, the Model holds all the data, the Controller is the input mediator (yes, an example of the Mediator Pattern) between the Model and the outside world, and the View is what shows the Model to the outside world. There can be multiple Views. When a change occurs in the Model, the Views are notified of the change. Each View then pulls data from the Model to render that specific view.

At its most general, any event-based system is the Observer pattern in action. A subscriber to the event – the observer – receives notifications when something occurs (a change). The subscriber then reacts to that event as appropriate.

The Subject typically defines a minimal interface an Observer must implement to subscribe to change notifications. This interface can be literally an interface with one or more methods on it or it could be just a single function that is called (for a non-object-oriented approach).

The Observer knows what it is observing because it has to not only subscribe to the Subject but potentially access the Subject for data that may have changed. This knowledge of the Subject can be partially mitigated by defining an interface on the Subject the Observer can use to fetch data from the Subject.

There are two ways the Observer and the Subject can interact: 1) The Observer pulls data from the Subject in response to a change notification. 2) The Subject pushes the data to the Observer as part of the change notification.

The pull approach can be inefficient if multiple observers are observing the same Subject. When each observer gets the change notification, each observer fetches potentially the same data from the Subject, producing redundant data fetches. There is not a lot that can be done about this but at least the coupling is very loose between the Subject and the observers.

The push approach can be more efficient as the data is part of the change notification and needs to be computed only once, regardless of the number of observers. The question is how much data should be pushed to each observer and in what form. This can be made easier if the observers implement an interface known to the Subject with one or more methods to be called as part of the process of sending the event notifications.

How to Use

Links to the Observer classes and interfaces
C++ C# Python C
IObserverNumberChanged interface IObserverNumberChanged interface IObserverNumberChanged interface Not Applicable
INumberProducer interface INumberProducer interface INumberProducer interface Not Applicable
IEventNotifications interface IEventNotifications interface IEventNotifications interface Not Applicable
ObserverSubject_NumberProducer class ObserverSubject_NumberProducer class ObserverSubject_NumberProducer class NumberProducer structure
NumberProducer_Create()
NumberProducer_Destroy()
ObserverForDecimal class ObserverForDecimal class ObserverForDecimal class ObserverForDecimal_NumberChanged()
ObserverForHexaDecimal class ObserverForHexaDecimal class ObserverForHexaDecimal class ObserverForHexadecimal_NumberChanged()
ObserverForBinary class ObserverForBinary class ObserverForBinary class ObserverForBinary_NumberChanged()

In this example of the Observer pattern, a Subject contains a numerical value that can change. There are three observers to the subject who are notified whenever the value changes. Each observer pulls the number from the Subject (for C++, C#, and Python) or is pushed the number (for C) and then displays the number in a different base. Typically these observers would run on different threads but in the interest of keeping things readable, everything runs on the same thread. The order of the output is dictated by the order of the observers subscribing to the Subject.

Note: For C++, C#, and Python, this example could be made simpler by having the Subject push the data to the observers, as shown in the example for C. I wanted to show the more complex form of the Observer pattern, however, so I went with a pull model.

As the C example suggests, the push model would have eliminated the need for the INumberProducer interface on the Subject as well as the need to take and store the INumberProducer object in each observer. And that in turn would simplify each observer class down to a single method to support the IObserverNumberChanged interface.

C++

void Observer_Exercise()
{
std::cout << std::endl;
std::cout << "Observer Exercise" << std::endl;
INumberProducer::shared_ptr_t numberProducer = std::make_shared<ObserverSubject_NumberProducer>();
// The number producer is passed to the observers so the observers
// can get the number to display. The observers only see the
// INumberProducer interface, to minimize knowledge about the
// Subject.
IObserverNumberChanged::shared_ptr_t observerDecimal = std::make_shared<ObserverForDecimal>(numberProducer);
IObserverNumberChanged::shared_ptr_t observerHexadecimal = std::make_shared<ObserverForHexaDecimal>(numberProducer);
IObserverNumberChanged::shared_ptr_t observerBinary = std::make_shared<ObserverForBinary>(numberProducer);
// Tell the number producer about the observers who are notified
// whenever the value changes.
IEventNotifications* eventNotifier = dynamic_cast<IEventNotifications*>(numberProducer.get());
if (eventNotifier != nullptr)
{
eventNotifier->SubscribeToNumberChanged(observerDecimal);
eventNotifier->SubscribeToNumberChanged(observerHexadecimal);
eventNotifier->SubscribeToNumberChanged(observerBinary);
}
// Call the number producer's Update() method a number of times.
// The observers automatically print out the current value in
// different bases.
for (int index = 0; index < 10; ++index)
{
std::cout
<< Helpers::formatstring(" Update %d on number producer. Results from observers:", index)
<< std::endl;
numberProducer->Update();
}
if (eventNotifier != nullptr)
{
// When done, remove the observers from the number producer.
// It's always good to clean up after ourselves.
eventNotifier->UnsubscribeFromNumberChanged(observerDecimal);
eventNotifier->UnsubscribeFromNumberChanged(observerHexadecimal);
eventNotifier->UnsubscribeFromNumberChanged(observerBinary);
}
std::cout << " Done." << std::endl;
}
std::string formatstring(const char *fmt,...)
Use the given string and arguments to return a buffer containing the formatted string....

C#

public void Run()
{
Console.WriteLine();
Console.WriteLine("Observer Exercise");
ObserverSubject_NumberProducer numberProducer = new ObserverSubject_NumberProducer();
// The number producer is passed to the observers so the observers
// can get the number to display. The observers only see the
// INumberProducer interface, to minimize knowledge about the
// Subject.
ObserverForDecimal observerDecimal = new ObserverForDecimal(numberProducer);
ObserverForHexaDecimal observerHexadecimal = new ObserverForHexaDecimal(numberProducer);
ObserverForBinary observerBinary = new ObserverForBinary(numberProducer);
// Tell the number producer about the observers who are notified
// whenever the value changes.
IEventNotifications eventNotifier = numberProducer as IEventNotifications;
eventNotifier.SubscribeToNumberChanged(observerDecimal);
eventNotifier.SubscribeToNumberChanged(observerHexadecimal);
eventNotifier.SubscribeToNumberChanged(observerBinary);
// Call the number producer's Update() method a number of times.
// The observers automatically print out the current value in
// different bases.
for (int index = 0; index < 10; ++index)
{
Console.WriteLine(" Update {0} on number producer. Results from observers:", index);
numberProducer.Update();
}
// When done, remove the observers from the number producer.
// It's always good to clean up after ourselves.
eventNotifier.UnsubscribeFromNumberChanged(observerDecimal);
eventNotifier.UnsubscribeFromNumberChanged(observerHexadecimal);
eventNotifier.UnsubscribeFromNumberChanged(observerBinary);
Console.WriteLine(" Done.");
}

Python

def Observer_Exercise():
print()
print("Observer Exercise")
numberProducer = ObserverSubject_NumberProducer()
# The number producer is passed to the observers so the observers
# can get the number to display. The observers only see the
# INumberProducer interface, to minimize knowledge about the
# Subject.
observerDecimal = ObserverForDecimal(numberProducer)
observerHexadecimal = ObserverForHexaDecimal(numberProducer)
observerBinary = ObserverForBinary(numberProducer)
# Tell the number producer about the observers who are notified
# whenever the value changes.
numberProducer.SubscribeToNumberChanged(observerDecimal)
numberProducer.SubscribeToNumberChanged(observerHexadecimal)
numberProducer.SubscribeToNumberChanged(observerBinary)
# Call the number producer's Update() method a number of times.
# The observers automatically print out the current value in
# different bases.
for index in range(0, 10):
print(" Update {0} on number producer. Results from observers:".format(index))
numberProducer.Update();
# When done, remove the observers from the number producer.
# It's always good to clean up after ourselves.
numberProducer.UnsubscribeFromNumberChanged(observerDecimal)
numberProducer.UnsubscribeFromNumberChanged(observerHexadecimal)
numberProducer.UnsubscribeFromNumberChanged(observerBinary)
print(" Done.")

C

void Observer_Exercise(void)
{
printf("\nObserver_Exercise\n");
if (producer != NULL)
{
// Tell the number producer about the observers who are notified
// whenever the value changes.
if (subscribed)
{
}
if (subscribed)
{
}
// If everyone subscribed, trigger the observers
if (subscribed)
{
// Call the number producer's Update() method a number of times.
// The observers automatically print out the current value in
// different bases.
for (int index = 0; index < 10; ++index)
{
printf(" Update %d on number producer. Results from observers:\n", index);
}
}
// When done, remove the observers from the number producer.
// It's always good to clean up after ourselves.
producer = NULL;
}
printf(" Done.\n");
}
static void ObserverForDecimal_NumberChanged(uint32_t number)
Represents an observer that prints out the specified number from the Subject in decimal.
static void ObserverForHexadecimal_NumberChanged(uint32_t number)
Represents an observer that prints out the specified number from the Subject in hexadecimal.
static void ObserverForBinary_NumberChanged(uint32_t number)
Represents an observer that prints out the specified number from the Subject in binary.
bool NumberProducer_SubscribeToNumberChanged(NumberProducer *producer, NumberChangedFunction observer)
Subscribe to the given NumberProducer to received changes to that producer's number....
void NumberProducer_UpdateNumber(NumberProducer *producer)
Update the number in the given NumberProducer object, triggering a call to all observer in the produc...
void NumberProducer_UnsubscribeFromNumberChanged(NumberProducer *producer, NumberChangedFunction observer)
Unsubscribe from the Given NumberProducer so the given observer will no longer be called when the pro...
void NumberProducer_Destroy(NumberProducer *producer)
Destroy the given instance of a NumberProducer object. After this function returns,...
NumberProducer * NumberProducer_Create(uint32_t number)
Create an instance of the NumberProducer structure and initialize the structure with the specified nu...
Represents the Subject in this example. In this case, a structure that contains a list of observers a...

RUST

(Apologies. Doxygen does not understand Rust syntax and therefore cannot colorize the code.)

pub fn observer_exercise() -> Result<(), String> {
println!("");
println!("Observer Exercise");
let mut number_producer = ObserverNumberProducer::new();
let observer_decimal = ObserverDecimal::new();
let observer_hexadecimal = ObserverHexadecimal::new();
let observer_binary = ObserverBinary::new();
// Add all observers to the number producer.
number_producer.add_observer(&observer_decimal);
number_producer.add_observer(&observer_hexadecimal);
number_producer.add_observer(&observer_binary);
// Call the number producer's update() method a number of times.
// The observers automatically print out the current value in
// different bases.
for index in 0..10 {
println!(" update {0} on number producer. Results from observers:", index);
number_producer.update();
}
// When done, remove the observers from the number producer.
// It's always good to clean up after ourselves.
number_producer.remove_observer(&observer_binary);
number_producer.remove_observer(&observer_hexadecimal);
number_producer.remove_observer(&observer_decimal);
println!(" Done.");
Ok(())
}

See Also