
Наблюдатель на C++
Наблюдатель — это поведенческий паттерн, который позволяет объектам оповещать другие объекты об изменениях своего состояния.
При этом наблюдатели могут свободно подписываться и отписываться от этих оповещений.
Сложность:
Популярность:
Применимость: Наблюдатель можно часто встретить в C++ коде, особенно там, где применяется событийная модель отношений между компонентами. Наблюдатель позволяет отдельным компонентам реагировать на события, происходящие в других компонентах.
Признаки применения паттерна: Наблюдатель можно определить по механизму подписки и методам оповещения, которые вызывают компоненты программы.
Концептуальный пример
Этот пример показывает структуру паттерна Наблюдатель, а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.
main.cc: Пример структуры паттерна
/** * Паттерн Наблюдатель * * Назначение: Создаёт механизм подписки, позволяющий одним объектам следить и * реагировать на события, происходящие в других объектах. * * Обратите внимание, что существует множество различных терминов с похожими * значениями, связанных с этим паттерном. Просто помните, что Субъекта также * называют Издателем, а Наблюдателя часто называют Подписчиком и наоборот. * Также глаголы «наблюдать», «слушать» или «отслеживать» обычно означают одно и * то же. */ #include <iostream> #include <list> #include <string> class IObserver { public: virtual ~IObserver(){}; virtual void Update(const std::string &message_from_subject) = 0; }; class ISubject { public: virtual ~ISubject(){}; virtual void Attach(IObserver *observer) = 0; virtual void Detach(IObserver *observer) = 0; virtual void Notify() = 0; }; /** * Издатель владеет некоторым важным состоянием и оповещает наблюдателей о его * изменениях. */ class Subject : public ISubject { public: virtual ~Subject() { std::cout << "Goodbye, I was the Subject.\n"; } /** * Методы управления подпиской. */ void Attach(IObserver *observer) override { list_observer_.push_back(observer); } void Detach(IObserver *observer) override { list_observer_.remove(observer); } void Notify() override { std::list<IObserver *>::iterator iterator = list_observer_.begin(); HowManyObserver(); while (iterator != list_observer_.end()) { (*iterator)->Update(message_); ++iterator; } } void CreateMessage(std::string message = "Empty") { this->message_ = message; Notify(); } void HowManyObserver() { std::cout << "There are " << list_observer_.size() << " observers in the list.\n"; } /** * Обычно логика подписки – только часть того, что делает Издатель. Издатели * часто содержат некоторую важную бизнес-логику, которая запускает метод * уведомления всякий раз, когда должно произойти что-то важное (или после * этого). */ void SomeBusinessLogic() { this->message_ = "change message message"; Notify(); std::cout << "I'm about to do some thing important\n"; } private: std::list<IObserver *> list_observer_; std::string message_; }; class Observer : public IObserver { public: Observer(Subject &subject) : subject_(subject) { this->subject_.Attach(this); std::cout << "Hi, I'm the Observer \"" << ++Observer::static_number_ << "\".\n"; this->number_ = Observer::static_number_; } virtual ~Observer() { std::cout << "Goodbye, I was the Observer \"" << this->number_ << "\".\n"; } void Update(const std::string &message_from_subject) override { message_from_subject_ = message_from_subject; PrintInfo(); } void RemoveMeFromTheList() { subject_.Detach(this); std::cout << "Observer \"" << number_ << "\" removed from the list.\n"; } void PrintInfo() { std::cout << "Observer \"" << this->number_ << "\": a new message is available --> " << this->message_from_subject_ << "\n"; } private: std::string message_from_subject_; Subject &subject_; static int static_number_; int number_; }; int Observer::static_number_ = 0; void ClientCode() { Subject *subject = new Subject; Observer *observer1 = new Observer(*subject); Observer *observer2 = new Observer(*subject); Observer *observer3 = new Observer(*subject); Observer *observer4; Observer *observer5; subject->CreateMessage("Hello World! :D"); observer3->RemoveMeFromTheList(); subject->CreateMessage("The weather is hot today! :p"); observer4 = new Observer(*subject); observer2->RemoveMeFromTheList(); observer5 = new Observer(*subject); subject->CreateMessage("My new car is great! ;)"); observer5->RemoveMeFromTheList(); observer4->RemoveMeFromTheList(); observer1->RemoveMeFromTheList(); delete observer5; delete observer4; delete observer3; delete observer2; delete observer1; delete subject; } int main() { ClientCode(); return 0; }
Output.txt: Результат выполнения
Hi, I'm the Observer "1". Hi, I'm the Observer "2". Hi, I'm the Observer "3". There are 3 observers in the list. Observer "1": a new message is available --> Hello World! :D Observer "2": a new message is available --> Hello World! :D Observer "3": a new message is available --> Hello World! :D Observer "3" removed from the list. There are 2 observers in the list. Observer "1": a new message is available --> The weather is hot today! :p Observer "2": a new message is available --> The weather is hot today! :p Hi, I'm the Observer "4". Observer "2" removed from the list. Hi, I'm the Observer "5". There are 3 observers in the list. Observer "1": a new message is available --> My new car is great! ;) Observer "4": a new message is available --> My new car is great! ;) Observer "5": a new message is available --> My new car is great! ;) Observer "5" removed from the list. Observer "4" removed from the list. Observer "1" removed from the list. Goodbye, I was the Observer "5". Goodbye, I was the Observer "4". Goodbye, I was the Observer "3". Goodbye, I was the Observer "2". Goodbye, I was the Observer "1". Goodbye, I was the Subject.