Skip to content

Instantly share code, notes, and snippets.

@caiorss
Created September 3, 2020 21:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save caiorss/ff0cb5ac26bba23fc4c17c8bb8df070d to your computer and use it in GitHub Desktop.
Save caiorss/ff0cb5ac26bba23fc4c17c8bb8df070d to your computer and use it in GitHub Desktop.
Observer desing pattern - functional programming way (Callbacks)
cmake_minimum_required(VERSION 3.9)
project(observer-design-pattern2)
#====== Global Configurations ==================#
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt5 COMPONENTS Core Widgets REQUIRED)
#=============== Target Configurations ============#
add_executable( observer2 observer-pattern2.cpp )
target_link_libraries( observer2 Qt5::Core Qt5::Gui Qt5::Widgets)
#include <iostream>
#include <iomanip>
#include <functional>
#include <QtWidgets>
#include <QApplication>
#include <QSysInfo>
using ObserverCallback = std::function<void (void* sender)>;
struct IObservable
{
/** Subscribe to observable notifications */
virtual void addObserver(ObserverCallback obs) = 0;
/** Notify all observers */
virtual void notify() = 0;
virtual ~IObservable() = default;
};
class Observable: public IObservable
{
void* m_sender = nullptr;
std::vector<ObserverCallback> m_observers{};
public:
Observable(){ }
Observable(void* sender): m_sender(sender){ }
void addObserver(ObserverCallback callback) override
{
m_observers.push_back(callback);
callback(m_sender);
}
/** Notify all observers */
void notify() override
{
for(const auto callback: m_observers){ callback(m_sender); }
}
};
class CounterModel
{
int m_counter{0};
Observable m_obs{this};
public:
void increment() { m_counter += 1; m_obs.notify(); }
void decrement() { m_counter -= 1; m_obs.notify(); }
int get() const { return m_counter; }
void onCounterChanged(ObserverCallback callback)
{
m_obs.addObserver(callback);
}
};
class FormView {
QWidget m_win{};
QFormLayout* m_form;
QPushButton* m_btn_increment;
QPushButton* m_btn_decrement;
QLabel* m_label;
CounterModel& m_model;
public:
FormView(CounterModel& model): m_model(model)
{
m_win.setWindowTitle("Form View");
m_form = new QFormLayout(&m_win);
m_btn_increment = new QPushButton("[+]");
m_btn_decrement = new QPushButton("[-]");
m_label = new QLabel("0");
m_form->addRow("Increment", m_btn_increment);
m_form->addRow("Decrement", m_btn_decrement);
m_form->addRow("Counter value", m_label);
m_win.show();
/** ------ Setup event handlers ------------------- **/
QObject::connect(m_btn_decrement, &QPushButton::clicked,
[self = this]{
self->m_model.decrement();
});
QObject::connect(m_btn_increment, &QPushButton::clicked,
[this](){
m_model.increment();
});
}
void update(void* sender)
{
int cnt = reinterpret_cast<CounterModel*>(sender)->get();
m_label->setText(QString::number(cnt));
std::cout << " [QT GUI] Counter state changed to = " << cnt << '\n';
}
};
class LabelView
{
QLabel m_label;
public:
LabelView()
{
m_label.setWindowTitle("Label View");
m_label.resize(400, 300);
m_label.show();
}
void notify(void* sender)
{
int cnt = reinterpret_cast<CounterModel*>(sender)->get();
m_label.setText(" [LABEL Observer] Counter value = " + QString::number(cnt));
}
};
int main(int argc, char** argv)
{
QApplication app(argc, argv);
CounterModel model;
model.onCounterChanged([](void* sender){
int cnt = static_cast<CounterModel*>(sender)->get();
std::cout << " [CONSOLE VIEW] Counter state changed to = " << cnt << '\n';
});
FormView observerB{model};
LabelView observerC{};
model.onCounterChanged([&](void* sender){
observerB.update(sender);
});
model.onCounterChanged([&](void* sender){
observerC.notify(sender);
});
return app.exec();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment