Click here to Skip to main content
15,909,373 members
Articles / Programming Languages / C++

Understanding and Implementing Observer Pattern in C++

Rate me:
Please Sign up or sign in to vote.
4.72/5 (23 votes)
25 Mar 2012CPOL2 min read 225.1K   1.6K   39   29
This article presents the basics of Observer Pattern, when to use it and how to implement it in C++.

Introduction

This article presents the basics of Observer Pattern, when to use it and how to implement it in C++. I have posted a similar article that talks about the Observer pattern in C#. The main aim of this article will be to implement the observer pattern in C++.

Background

Many a times, we need one part of our application updated with the status of some other part of the application. One way to do this is to have the receiver part repeatedly check the sender for updates but this approach has two main problems. First, it takes up a lot of CPU time to check the new status and second, depending on the interval we are checking for change we might not get the updates "immediately".

This problem has one easy solution, i.e., Observer Pattern. This is my own second article on Observer Pattern. I have a similar article talking about Observer Implementation in C#. I think this article is also worth sharing, as it could be useful for the C++ beginners and also the valuable comments I get on the article will let me learn more.

Here is the class diagram for Observer Pattern(Reference:  GoF Design Patterns)

Image 1

Using the Code

Let us now discuss all the classes one by one:

  • Subject: This class keeps track of all the observers and provides the facility to add or remove the observers. Also it is the class that is responsible for updating the observers when any change occurs. In our solution, we have ASubject implemented for the same purpose.
  • ConcreteSubject: This class is the real class that implements the Subject. This class is the entity whose change will affect other objects. We have DummyProject class implemented for the same.
  • Observer: This represents an interface that defines the method that should be called whenever there is change. We have implemented this as IObserver.
  • ConcreteObserver: This is the class which needs to keep itself updated with the change. This class just needs to implement the Observer and register itself with the ConcreteSubject and it is all set to receive the updates. We have Shop class in our application serving the same purpose.

The Subject: ASubject

C++
//Header File
#pragma once
#include <vector>
#include <list>
#include "shop.h"

class ASubject
{
    //Lets keep a track of all the shops we have observing
    std::vector<Shop*> list;

public:
    void Attach(Shop *product);
    void Detach(Shop *product);
    void Notify(float price); 
};

//CPP File
#include "ASubject.h"
#include <algorithm>

using namespace std;

void ASubject::Attach(Shop *shop)
{
    list.push_back(shop);
}
void ASubject::Detach(Shop *shop)
{    
    list.erase(std::remove(list.begin(), list.end(), shop), list.end());    
}

void ASubject::Notify(float price)
{
    for(vector<Shop*>::const_iterator iter = list.begin(); iter != list.end(); ++iter)
    {
        if(*iter != 0)
        {
            (*iter)->Update(price);
        }
    }
}

The ConcreteSubject: DummyProduct

C++
//Header File
#pragma once
#include "ASubject.h"

class DummyProduct : public ASubject
{
public:
    void ChangePrice(float price);
};

//CPP File
#include "DummyProduct.h"

void DummyProduct::ChangePrice(float price)
{
    Notify(price);
}

The Observer: IObserver

C++
#pragma once

class IObserver
{
public:
    virtual void Update(float price) = 0;
};

The ConcreteObserver: Shop

C++
//Header File
#pragma once
#include <iostream>
#include <string>
#include "IObserver.h"

class Shop : IObserver
{
    //Name of the Shop
    std::string name;
    float price;
public:
    Shop(std::string n); 
    void Update(float price);          
};

//CPP File
#include "Shop.h"

Shop::Shop(std::string name)
{
    this->name = name;
}

void Shop::Update(float price)
{
    this->price = price;

    //Lets print on console just to test the working
    std::cout << "Price at "<< name << " is now "<< price << "\n";
}

Testing the Code

C++
int main(int argc, char* argv[])
{
    DummyProduct product;
                    
    // We have four shops wanting to keep updated price set by product owner
    Shop shop1("Shop 1");
    Shop shop2("Shop 2");

    product.Attach(&shop1);
    product.Attach(&shop2);

    //Now lets try changing the products price, this should update the shops automatically
    product.ChangePrice(23.0f);

    //Now shop2 is not interested in new prices so they unsubscribe
    product.Detach(&shop2);            

    //Now lets try changing the products price again
    product.ChangePrice(26.0f);

    getchar();
    return 0;
}

Points of Interest

This article covers the basics of Observer pattern and provides a basic implementation in C++. I have also implemented the same in C#. What I learnt from it is how the observer pattern works and what are the similarities and differences in implementing it in C++ and C#.

History

  • 10 Feb, 2012: Simple and rudimentary implementation of Observer pattern in C++
  • 26 March 2012: Changed the class diagram.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
India India

I Started my Programming career with C++. Later got a chance to develop Windows Form applications using C#. Currently using C#, ASP.NET & ASP.NET MVC to create Information Systems, e-commerce/e-governance Portals and Data driven websites.

My interests involves Programming, Website development and Learning/Teaching subjects related to Computer Science/Information Systems. IMO, C# is the best programming language and I love working with C# and other Microsoft Technologies.

  • Microsoft Certified Technology Specialist (MCTS): Web Applications Development with Microsoft .NET Framework 4
  • Microsoft Certified Technology Specialist (MCTS): Accessing Data with Microsoft .NET Framework 4
  • Microsoft Certified Technology Specialist (MCTS): Windows Communication Foundation Development with Microsoft .NET Framework 4

If you like my articles, please visit my website for more: www.rahulrajatsingh.com[^]

  • Microsoft MVP 2015

Comments and Discussions

 
SuggestionUsing templates Pin
John Wellbelove13-Feb-12 22:15
John Wellbelove13-Feb-12 22:15 
GeneralMy vote of 4 Pin
KjellKod.cc13-Feb-12 10:20
KjellKod.cc13-Feb-12 10:20 
GeneralRe: My vote of 4 Pin
Stefan_Lang14-Feb-12 0:41
Stefan_Lang14-Feb-12 0:41 
GeneralRe: My vote of 4 Pin
KjellKod.cc15-Feb-12 3:19
KjellKod.cc15-Feb-12 3:19 
GeneralRe: My vote of 4 Pin
Stefan_Lang16-Feb-12 23:12
Stefan_Lang16-Feb-12 23:12 
GeneralRe: My vote of 4 Pin
KjellKod.cc17-Feb-12 2:07
KjellKod.cc17-Feb-12 2:07 
GeneralRe: My vote of 4 Pin
Stefan_Lang17-Feb-12 4:25
Stefan_Lang17-Feb-12 4:25 
GeneralRe: My vote of 4 Pin
KjellKod.cc17-Feb-12 6:06
KjellKod.cc17-Feb-12 6:06 
Stefan_Lang wrote:
In the end, what pattern you should use depends on the problem at hand

Well said Stefan!

Stefan_Lang wrote:

KjellKod.cc wrote:
There is nothing to stop you from using signals-n-slots and using a connect/disconnect though an interface is there?


Yes, in fact there is: As I pointed out, the connection in that case I mentioned often depended on the observers inner state. That means any external object activating or deactivating that connection would have had to be notified of a change of that state, turning it into an observer! It would be rather ironic to decouple an observer from its duty to maintain its connections by introducing an observer to that observer!


I agree to disagree Wink | ;) [1, 2 and 3]
1. At least in the scenario that the data-stream to be shuffled by a connection is more frequent than the need for the Observer to start/stop listening to the data stream.

2. KSignal Hypotechical Technical Reasoning:
There is also the possibility of course (signal-n-slot implementation dependent) that the slot is a physical entity in your object. Owned by composition by the Observer. That's nothing to stop one from putting in an inActive_ flag in the slot to stop it from pushing the data to the Observer. Yes it would be overhead as the call to the slot would be made,. but (see below for thread discussion) in the no-thread-to-thread scenario that overhead would be minuscule.

3. Similar to 2. The Observer receives the data but has internal state that lets it to ignore it.

Stefan_Lang wrote:
there was a notable cost for extra traffic between threads, context switching, waking up sleeping threads unnecessarily, and the like. Therefore minimizing communication was top priority.
Ah. This is the core of the issue I think. It would be interesting to see a sketch outline of the Observer pattern you used. As the pattern in its raw form show nothing of thread-to-thread communication. Obviously the Observer pattern as shown in the article above cannot be used for thread-to-thread communication...

Qt's (the originator for the term signal-n-slot) signal-n-slot does implement safe thread-to-thread communication. In fact it is to me the only known thread-safe signal-and-slot communication scheme since it uses thread-safe "signal-message" queues towards the Qt wrapped thread. (This was going to be the next feature for ksignals. I only need a paid excuse to do it. Anyone need it with C++11? ... Please Blush | :O )

One "interesting" use of Observer pattern that I have seen was also done for communication between threads (and Corba-like distributed objects). They used a demultiplexor inspired way to avoid using multiple inheritance. A frequent bug that keep popping up was that non-thread-safe Subject-Observer communication was used where the more hard to use thread-Corba-safe Observer should be used. I.e. it led to two or more threads creating interesting races as they called through inheritance into other objects.


Did you guys hook up the Observer to some kind of queued message passing? Or was it up to the implementation in the Observer to have thread-safe receive of the data by using a mutex or similar?. There are a number of different way it can be done. I have seen a couple. It would be interesting to know what you guys did. It can be tricky, slow and dangerous to use inheritance to deliver messages between threads.
QuestionGood Article Pin
godistwo11-Feb-12 5:31
godistwo11-Feb-12 5:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.