🔭Observer

The Observer pattern provides a way to subscribe and unsubscribe to and from these events for any object that implements a subscriber interface.

Observer is a behavioral design pattern that allows some objects to notify other objects about changes in their state.

Usage examples

The Observer pattern is pretty common in C++ code, especially in the GUI components. It provides a way to react to events happening in other objects without coupling to their classes.

Identification

The pattern can be recognized by subscription methods, that store objects in a list, and by calls to the update method issued to objects in that list.

Pros & Cons

Graphic Visual

Flow of Observer
Settimana Enigmistica Style

Example

The following example shows the structure of the Observer design pattern, focusing on answering these questions:

  • What classes does it consist of?

  • What roles do these classes play?

  • In what way elements of the pattern are related?

Conceptual example

main.cpp

#include <iostream>
#include <list>
#include <string>

class IObserver { 
    //define Observer Interface
    //good practice when dealing with inheritance
    public:
        virtual ~IObserver(){}; //virtual destructor
        //pure (=0) virtual method
        virtual void Update(const std::string &message_from_subject) = 0;
};

class ISubject {
//define Subject Interface
    public:
        virtual ~ISubject(){}; //virtual destructor
//Pure virtual methods
//Defines a way to attach (register) an observer object to the subject.
//It takes a pointer to an IObserver object as input.
        virtual void Attach(IObserver *observer) = 0; 
//Defines a way to detach (unregister) an observer object from the subject.
//It also takes a pointer to an IObserver object as input.
        virtual void Detach(IObserver *observer) = 0;
//Defines a way for the subject to notify all attached observers.
//Typically involves sending some data to the registered observers.
        virtual void Notify() = 0;
};


/*
  The Subject owns some important state and notifies observers when the state
  changes.
 */
 
class Subject : public ISubject {
//creates a derived class from ISubject
  public:
//define desrtuctor behavior
    virtual ~Subject() {
    std::cout << "Goodbye, I was the Subject.";
    }

/**
 * The subscription management methods.
 */
    void Attach(IObserver *observer) override {
//add the observer at the end of the observer list
    list_observer_.push_back(observer);
    }
    
    void Detach(IO *observer) override {
//remove the observer from the observer list
    list_observer_.remove(observer);
    }
    
    void Notify() override {
//reach the start of the observer list
    std::list<IObserver *>::iterator iterator = list_observer_.begin();
    HowManyObserver();
    while (iterator != list_observer_.end()) {
        (*iterator)->Update(message_);
        ++iterator;
        }
    }
    
    
    void CreateMessage(std::string message = "Empty") {
      this->message_ = message;
      Notify();
    }
        
    void HowManyObserver(){
    //print out how many observers are listening
    std::cout << "There are" << list_observer_.size() << " observers in the list";
    }
    
/*
 * Usually, the subscription logic is only a fraction of what a Subject can
 * really do. Subjects commonly hold some important business logic, that
 * triggers a notification method whenever something important is about to
 * happen (or after it).
*/
    void SomeBusinessLogic(){
    this->message_ = "change message";
    Notify();
    std::cout << "I'm about to do some cool things, wow!";
    }
    
  private:
    std::list<IObserver *> list_observer_;
    std:: message_;
    };

class Observer : public IObserver {
  public:
    Observer(Subject &subject) : subject_(subject) {
      this->subject_.Attach(this);
      std::cout << "I'm the Observer" << ++Observer::static_number_ << ".";
      this->number_ = Observer::static_number_;
    }
    
    virtual ~Observer(){
      std::cout << "Goodbye, I was the Observer " << this->number_ << ".";
    }
      
    void Update(const std::string &message_from_subject) override {
    message_from_subject_ = message_from_subject;
    PrintInfo();
    }
    
    void RemoveMeFromTheList() {
    subject_.Detach(this);
    std::cout << "Observer \"" << number_ << "\" removed from the list.\n";
    }
    
    void PrintInfo() {
    std::cout << "Observer " << this->number_ << this->message_from_subject_;
    }
    
  private:
    std::string message_from_subject_;
    Subject &subject_;
    static int static_number_;
    int number_;
};

int Observer::static_number_ = 0;

void ClientCode() {
  Subject *subject = new Subject;
  Observer *observer1 = new Observer(*subject);
  Observer *observer2 = new Observer(*subject);
  Observer *observer3 = new Observer(*subject);
  Observer *observer4;
  Observer *observer5;

  subject->CreateMessage("Hello World! :D");
  observer3->RemoveMeFromTheList();

  subject->CreateMessage("The weather is hot today! :p");
  observer4 = new Observer(*subject);

  observer2->RemoveMeFromTheList();
  observer5 = new Observer(*subject);

  subject->CreateMessage("My new car is great! ;)");
  observer5->RemoveMeFromTheList();

  observer4->RemoveMeFromTheList();
  observer1->RemoveMeFromTheList();

  delete observer5;
  delete observer4;
  delete observer3;
  delete observer2;
  delete observer1;
  delete subject;
}

int main() {
  ClientCode();
  return 0;
}

Last updated