Observer Design Pattern in Arduino

Observer Design Pattern in Arduino.md

1. Introduction

In this post, we are going to explore observer design pattern in Arduino board. Yes. We can use callback function and this will make it easier. But the problem is the callback function has to be static and so far we can’t use std::function (standard c++ library) in Arduino board.

Be warned that what we are going to see later is not full–fledged observer design pattern. We can’t assign multiple observers for this code. We can only assign only one observer for now. We are not going to add multiple observers here to make the observer pattern as simple as possible. However, adding/removing multiple observers can be done using object array and proper tracking of objects.

Download

The whole project can be found from this github.

2. Environment

The project is built using Microsoft Visual Studio with Visualmicro plugin. You can use any available IDE either in Microsoft or Linux environment. The job of IDE here is to help you to write your design logic faster without going through error checking and so on.

3. Class Design

Observer Pattern

We only have three classes here.

  • Observer
  • ObserverTester (Concrete class)
  • Subject

The above UML diagram [retrieved from wikipedia] will clarify the idea. One thing to take note is that we are talking about the observer pattern here, not publish-subscribe pattern which is using different approach to get an update. The pattern design here is that the observer will first attach the subject to itself. When subject wants to notify some updated data due to change in value, the subject will notify the observer. Once the observer get notified, the observer will perform necessary actions based on the received value. The ObserverTester is derived from the observer so that different derived observers can maintain as the observer pattern.

3.1 Observer class

First we will look at the Observer class. This class is the base class and it only has one function and one virtual function.

Observer.h

class Subject;

class Observer {
public:
    void attachSubject(Subject *subject);
    virtual void onReceivedDataFromSubject(const Subject*) = 0;
};

Observer.cpp

#include "Observer.h"
#include "Subject.h"

void Observer::attachSubject(Subject * subject) {
    subject->registerObserver(this);
}

3.2 Subject

The subject class can register and unregister a observer and it can hold an observer. It will notify an observer if there is a change in value.

Subject.h

class Observer;

class Subject {
public:
    Subject();
    void registerObserver(Observer*); 
    void unregisterObserver();
    int getValue() const;
    void setVal(const int val);

private:
    int mValue;
    void _notifyObserver();
    Observer* mObserver;
};

Subject.cpp

#include "Subject.h"
#include "Observer.h"

Subject::Subject() {
}

void Subject::registerObserver(Observer* obs) {
    mObserver = obs; //we will only allow one observer
}

void Subject::unregisterObserver() {
    mObserver = nullptr;
}

int Subject::getValue() const {
    return mValue;
}

void Subject::_notifyObserver() {
    if (mObserver != nullptr) {
        mObserver->onReceivedDataFromSubject(this); 
    }
}

void Subject::setVal(const int val) {
    mValue = val;
    _notifyObserver(); //since there is a change in value, notify the observer
}

3.3 ObserverTester

The ObserverTester is derived from Observer class and has to override onReceivedDataFromSubject function. Upon arriving data from the subject, the observerTester print out data which is from Subject instance.

ObserverTester.h

#include "Observer.h"
class ObserverTester : public Observer
{
    void onReceivedDataFromSubject(const Subject*) override;
};

ObserverTester.cpp

#include "ObserverTester.h"
#include "Subject.h"

void ObserverTester::onReceivedDataFromSubject(const Subject *sub) {
    Serial.print("Value is "); Serial.println(sub->getValue());
}

3.4 Observer Pattern Test

This is the ino Arduino file to run using observer pattern class. We only need Serial port to monitor the value. Make sure set the baud rate to 115200 on the serial monitor to see the value correctly.

As mentioned eailer, the ObserverTester will first attach Subject. We will change data of subject by setting value using setVal function. This will cause the subject to notify the observerTester. The observerTester then print out the data of subject on the serial monitor.

Remember that the subject can register and unregister an observer. After the subject unregistered the observerTester from itself using unregisterObserver() function, the observerTest will no longer receive any update from the subject.

Once the subject registered again using registerObserver(&observerTester) function, the observerTester will receive the data from the subject again.

ObserverPattenTest.ino

#include "ObserverTester.h"
#include "Observer.h"
#include "Subject.h"

Subject subject;
ObserverTester observerTester;

void setup()
{
    Serial.begin(115200);
    observerTester.attachSubject(&subject);
}

void loop()
{

    for (int i = 0; i < 10; i++) {
        subject.setVal(i); //this will print data on Serial Monitor
        delay(500);
    }

    Serial.println("Going to unregister Observer");
    subject.unregisterObserver();

    for (int i = 0; i < 10; i++) {
        subject.setVal(i); // we will not be seeing any value on Serial Monitor because we unregister Observer
        delay(500);
    }

    Serial.println("Going to register Observer again");
    subject.registerObserver(&observerTester);
}