Created
November 21, 2021 11:16
-
-
Save HanatoK/7e0971dcf593153c65f93fa24c9a9d0c to your computer and use it in GitHub Desktop.
C++ observer pattern with smart pointers
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 <algorithm> | |
#include <vector> | |
#include <memory> | |
#include <string> | |
class SubjectBase; | |
class ObserverBase { | |
public: | |
virtual ~ObserverBase() {} | |
virtual void update(const std::string& msg) = 0; | |
virtual void subscribe(std::shared_ptr<SubjectBase> subject) = 0; | |
virtual void unsubscribe() = 0; | |
}; | |
class SubjectBase { | |
public: | |
virtual ~SubjectBase() {} | |
virtual void attach(std::shared_ptr<ObserverBase> observer) = 0; | |
virtual void detach(std::shared_ptr<ObserverBase> observer) = 0; | |
virtual void notify() = 0; | |
virtual void prepareMessage(const std::string& s) = 0; | |
}; | |
class Subject: public SubjectBase { | |
public: | |
virtual ~Subject() { | |
std::cout << "(Subject) Destroy subject.\n"; | |
} | |
virtual void attach(std::shared_ptr<ObserverBase> observer) { | |
auto it = std::find(mObservers.begin(), mObservers.end(), observer); | |
if (it == mObservers.end()) { | |
mObservers.push_back(observer); | |
} else { | |
std::cout << "(Subject) Attach again, ignored.\n"; | |
} | |
} | |
virtual void detach(std::shared_ptr<ObserverBase> observer) { | |
auto it = std::find(mObservers.begin(), mObservers.end(), observer); | |
while (it != mObservers.end()) { | |
mObservers.erase(it); | |
it = std::find(mObservers.begin(), mObservers.end(), observer); | |
} | |
} | |
virtual void notify() { | |
for (auto& i: mObservers) { | |
i->update(mMessage); | |
} | |
} | |
virtual void prepareMessage(const std::string& s) { | |
mMessage = s; | |
} | |
private: | |
std::vector<std::shared_ptr<ObserverBase>> mObservers; | |
std::string mMessage; | |
}; | |
class Observer: public ObserverBase, public std::enable_shared_from_this<Observer> { | |
public: | |
Observer() { | |
static int id = 0; | |
mIndex = id++; | |
} | |
virtual ~Observer() { | |
std::cout << "(Observer " << mIndex << ") Bye!\n"; | |
} | |
virtual void subscribe(std::shared_ptr<SubjectBase> s) { | |
if (auto subject = mSubject.lock()) { | |
std::cout << "(Observer " << mIndex << "): Already subscribed.\n"; | |
} else { | |
mSubject = s; | |
s->attach(shared_from_this()); | |
} | |
} | |
virtual void update(const std::string& s) { | |
mMessage = s; | |
std::cout << "(Observer " << mIndex << "): " << mMessage << "\n"; | |
} | |
virtual void unsubscribe() { | |
if (auto subject = mSubject.lock()) { | |
subject->detach(shared_from_this()); | |
std::cout << "(Observer " << mIndex << ") Detached.\n"; | |
mSubject.reset(); | |
} else { | |
std::cout << "(Observer " << mIndex << ") Unable to detach or already detached.\n"; | |
} | |
} | |
private: | |
std::weak_ptr<SubjectBase> mSubject; | |
std::string mMessage; | |
int mIndex; | |
}; | |
int main() { | |
std::shared_ptr<SubjectBase> subject = std::make_unique<Subject>(); // or from a factory pattern | |
subject->prepareMessage("Hello!"); | |
std::shared_ptr<ObserverBase> o1 = std::make_unique<Observer>(); // or from a factory pattern | |
std::shared_ptr<ObserverBase> o2 = std::make_unique<Observer>(); // or from a factory pattern | |
std::cout << "Round 1\n"; | |
o1->subscribe(subject); | |
o2->subscribe(subject); | |
o2->subscribe(subject); | |
subject->notify(); | |
std::cout << "Round 2\n"; | |
o2->unsubscribe(); | |
o2->unsubscribe(); | |
subject->notify(); | |
std::cout << "Round 3\n"; | |
o2->subscribe(subject); | |
subject->notify(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment