#include #include #include #include #include #include #include template struct Observer { // First, we don't need to use polymorphism, so also virtual D'tor is redundant using OnUpdate = std::function; 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; 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 _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 = std::make_unique(); 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); }