-
-
Save caiorss/9331193ae1f9b05e4949160a4e024e84 to your computer and use it in GitHub Desktop.
Observer design pattern - implementation 1
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-pattern1) | |
#====== 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( observer1 observer-pattern1.cpp ) | |
target_link_libraries( observer1 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 <QtWidgets> | |
#include <QApplication> | |
#include <QSysInfo> | |
struct IObserver; | |
struct IObservable | |
{ | |
/** Subscribe to observable notifications */ | |
virtual void addObserver(IObserver* obs) = 0; | |
/** Notify all observers */ | |
virtual void notify() = 0; | |
virtual ~IObservable() = default; | |
}; | |
struct IObserver | |
{ | |
virtual void update(IObservable* sender) = 0; | |
virtual ~IObserver() = default; | |
}; | |
class BasicObservable: public IObservable | |
{ | |
std::vector<IObserver*> m_observers{}; | |
public: | |
void addObserver(IObserver* obs) override | |
{ | |
m_observers.push_back(obs); | |
obs->update(this); | |
} | |
/** Notify all observers */ | |
void notify() override | |
{ | |
for(const auto obs: m_observers){ obs->update(this); } | |
} | |
}; | |
class CounterModel: public BasicObservable | |
{ | |
int m_counter = 0; | |
public: | |
void increment() | |
{ | |
m_counter += 1; | |
this->notify(); | |
} | |
void decrement() | |
{ | |
m_counter -= 1; | |
this->notify(); | |
} | |
void reset() | |
{ | |
m_counter = 0; | |
this->notify(); | |
} | |
void set(int n) | |
{ | |
m_counter = n; | |
this->notify(); | |
} | |
int get() const { return m_counter; } | |
}; | |
/** Concrete observer that prints the subject state in the console (terminal) */ | |
class ConsoleView: public IObserver | |
{ | |
/* override: IObserver::update() */ | |
void update(IObservable* sender) override | |
{ | |
/* Note: It can result in undefined behavior. */ | |
int cnt = static_cast<CounterModel*>(sender)->get(); | |
std::cout << " [CONSOLE] Counter state changed to = " << cnt << '\n'; | |
} | |
}; | |
class FormView: public IObserver { | |
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(); | |
}); | |
} | |
/* override: IObserver::update() */ | |
void update(IObservable* sender) override | |
{ | |
int cnt = static_cast<CounterModel*>(sender)->get(); | |
m_label->setText(QString::number(cnt)); | |
std::cout << " [QT GUI] Counter state changed to = " << cnt << '\n'; | |
} | |
}; | |
class LabelView: public IObserver | |
{ | |
QLabel m_label; | |
public: | |
LabelView() | |
{ | |
m_label.setWindowTitle("Label View"); | |
m_label.resize(400, 300); | |
m_label.show(); | |
} | |
/* override: IObserver::update() */ | |
void update(IObservable* sender) override | |
{ | |
int cnt = static_cast<CounterModel*>(sender)->get(); | |
m_label.setText(" [LABEL Observer] Counter value = " + QString::number(cnt)); | |
} | |
}; | |
int main(int argc, char** argv) | |
{ | |
// Useful for debugging | |
std::cout << " [INFO] QTVersion = " << ::qVersion() << std::endl; | |
QApplication app(argc, argv); | |
CounterModel model; | |
ConsoleView observerA{}; | |
FormView observerB{model}; | |
LabelView observerC{}; | |
model.addObserver(&observerA); | |
model.addObserver(&observerB); | |
model.addObserver(&observerC); | |
return app.exec(); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment