-
-
Save caiorss/ff0cb5ac26bba23fc4c17c8bb8df070d to your computer and use it in GitHub Desktop.
Observer desing pattern - functional programming way (Callbacks)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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