101 lines
No EOL
2.6 KiB
C++
101 lines
No EOL
2.6 KiB
C++
#include <algorithm>
|
|
#include <cassert>
|
|
#include <functional>
|
|
#include <iostream>
|
|
#include <memory>
|
|
#include <set>
|
|
#include <vector>
|
|
|
|
template <typename Subject, typename State>
|
|
struct Observer {
|
|
// First, we don't need to use polymorphism, so also virtual D'tor is redundant
|
|
using OnUpdate = std::function<void(const Subject&, State)>;
|
|
|
|
explicit Observer(OnUpdate fun)
|
|
: _onUpdate(std::move(fun)) {}
|
|
void update(const Subject& subject, State state) {
|
|
std::invoke(_onUpdate, subject, state);
|
|
}
|
|
|
|
private:
|
|
OnUpdate _onUpdate;
|
|
};
|
|
|
|
class Browser;
|
|
|
|
enum class BrowserState {
|
|
Closing,
|
|
FocusChanged
|
|
};
|
|
|
|
using BrowserObserver = Observer<Browser, BrowserState>;
|
|
|
|
class Browser {
|
|
public:
|
|
void attach(BrowserObserver* observer) { _observers.emplace(observer); }
|
|
void detach(BrowserObserver* observer) { _observers.erase(observer); }
|
|
void setFocus(bool focus) {
|
|
if (std::exchange(_hasFocus, focus) != focus) {
|
|
notify(BrowserState::FocusChanged);
|
|
}
|
|
}
|
|
bool hasFocus() const { return _hasFocus; }
|
|
|
|
private:
|
|
void notify(BrowserState state) const {
|
|
std::ranges::for_each(_observers, [state, this](auto* observer) {
|
|
observer->update(*this, state);
|
|
});
|
|
}
|
|
|
|
bool _hasFocus{false};
|
|
std::set<BrowserObserver*> _observers;
|
|
};
|
|
|
|
class Extension {
|
|
public:
|
|
explicit Extension(const std::string& name)
|
|
: _name(name) {}
|
|
// D'tor is not needed neither the rule of 5
|
|
|
|
// dispatch message
|
|
void update(const Browser& browser, BrowserState state) {
|
|
switch (state) {
|
|
case BrowserState::Closing:
|
|
return;
|
|
case BrowserState::FocusChanged: {
|
|
if (browser.hasFocus()) {
|
|
displayExtension();
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
void displayExtension() {
|
|
std::cout << "This is an extension: " << _name << '\n';
|
|
}
|
|
|
|
std::string _name;
|
|
};
|
|
|
|
int main() {
|
|
std::unique_ptr<Browser> browser = std::make_unique<Browser>();
|
|
Extension extension1("A");
|
|
Extension extension2("B");
|
|
Extension extension3("C");
|
|
BrowserObserver observer1([&extension1](const Browser& browser, BrowserState state) {
|
|
extension1.update(browser, state);
|
|
});
|
|
BrowserObserver observer2([&extension2](const Browser& browser, BrowserState state) {
|
|
extension2.update(browser, state);
|
|
});
|
|
BrowserObserver observer3([&extension3](const Browser& browser, BrowserState state) {
|
|
extension3.update(browser, state);
|
|
});
|
|
browser->attach(&observer1);
|
|
browser->attach(&observer2);
|
|
browser->attach(&observer3);
|
|
browser->setFocus(true);
|
|
} |