Skip to content

Instantly share code, notes, and snippets.

@HanatoK
Created November 21, 2021 11:16
Show Gist options
  • Save HanatoK/7e0971dcf593153c65f93fa24c9a9d0c to your computer and use it in GitHub Desktop.
Save HanatoK/7e0971dcf593153c65f93fa24c9a9d0c to your computer and use it in GitHub Desktop.
C++ observer pattern with smart pointers
#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