Reference: refactoringguru. Cn/design – patt…
intentions
The Observer pattern is a behavior design pattern that allows you to define a subscription mechanism that notifies multiple other objects that “observe” an object when an event occurs.
The problem
Take User and the App Store for example. Let’s say a popular game is about to launch on the App Store, and some users care about when it will launch. So there are two ways to do it:
User
Check to see if the game is online every second. But that would be wastefulUser
A lot of time, and most of it for nothing.App Store
At the launch of the game, to allUser
Send notification emails. But this will disturb those who are not interested in the gameUser
.
The solution
We call an object that has some interesting state a publisher that notifies other objects of its state changes. These other objects that watch for changes in the publisher’s state are called subscribers.
Publishers maintain a list member variable for storing references to subscriber objects and methods for adding or removing subscribers. Each time the publisher status changes, the subscriber list is traversed and notifications are sent to subscribers.
All subscribers must implement the same interface through which the publisher interacts only with the subscriber. The notification method and its parameters must be declared in the interface so that the publisher can also pass some context data when issuing the notification.
Use the observer model to solve the problem. Define the App Store as a publisher, and users interested in an upcoming game as subscribers.
Observer pattern structure
- Publisher: A Publisher that sends noteworthy events to other objects. Events occur after the publisher’s own state changes or certain actions are performed.
- Subscriber: subscriber interface, which declares the notification interface. In most cases, this interface contains only one
update
Update method. - Concrete Subscriber: a specific Subscriber that can perform operations in response to a notification from the publisher. All concrete subscriber classes implement the same interface, so the publisher interacts only with the concrete subscriber through the interface, reducing the coupling.
- The Client creates publisher and subscriber objects, respectively, and registers publisher updates for subscribers.
Code implementation
#include<iostream>
#include<string>
#include<list>
using namespace std;
// All specific subscribers should implement the same interface
class IObserver {
public:
virtual ~IObserver() {}virtual void Update(const string &message_from_subject) = 0;
};
// Publisher interface
class ISubject {
public:
virtual ~ISubject() {}virtual void Attach(IObserver *observer) = 0;
virtual void Detach(IObserver *observer) = 0;
virtual void Notify(a) = 0;
};
class Subject : public ISubject {
private:
// The publisher maintains a list member variable used to store references to subscriber objects;
list<IObserver*> list_observer_;
string message_;
public:
virtual ~Subject()
{
std::cout << "Goodbye, I was the Subject.\n";
}
virtual void Attach(IObserver *observer) {
list_observer_.push_back(observer);
}
virtual void Detach(IObserver *observer) {
list_observer_.remove(observer);
}
virtual void Notify(a) {
list<IObserver*>::iterator it = list_observer_.begin(a);HowManyObserver(a);while(it! =list_observer_.end())
{
(*it)->Update(message_); ++it; }}// The notification method can be used to publish notifications to subscribers whenever a state change occurs
void CreateMessage(string message = "Empty") {
this->message_ = message;
Notify(a); }void HowManyObserver(a) {
cout << "There are " << list_observer_.size() < <" observers in the list" << endl;
}
void SomeBussinessLogic(a) {
this->message_ = "change message message";
Notify(a); cout <<"I'm about to do some thing importnat"<< endl; }};// Specific subscriber
class Observer :public IObserver {
private:
string message_from_subject_;
Subject &subject_;
static int static_number_;
int number_;
public:
// Bind publishers to subscribers via constructors
Observer(Subject &subject) : subject_(subject) {
this->subject_.Attach(this);
cout << "Hi, I'm the Observer \"" << ++Observer::static_number_ << "\".\n";
this->number_ = Observer::static_number_;
}
virtual ~Observer()
{
cout<<"Goodbye, I was the Observer \""<<this->number_<<"\"."<<endl;
}
virtual void Update(const string &message_from_subject) {
message_from_subject_ = message_from_subject;
PrintInfo(a); }void RemoveMeFromTheList(a) {
subject_.Detach(this);
cout << "Observer \"" << number_ << "\" removed from the list.\n";
}
void PrintInfo(a) {
cout << "Observer \"" << this->number_ << "\": a new message is available --> " << this->message_from_subject_ << "\n"; }};int Observer::static_number_ = 0;
// The client must generate all required subscribers and register with the appropriate publisher.
void ClientCode(a) {
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(a); subject->CreateMessage("The weather is hot today! :p");
observer4 = new Observer(*subject);
observer2->RemoveMeFromTheList(a); observer5 =new Observer(*subject);
subject->CreateMessage("My new car is great! ;) ");
observer5->RemoveMeFromTheList(a); observer4->RemoveMeFromTheList(a); observer1->RemoveMeFromTheList(a);delete observer5;
delete observer4;
delete observer3;
delete observer2;
delete observer1;
delete subject;
}
int main(a) {
ClientCode(a);return 0;
}
Copy the code
Advantages and disadvantages of this mode
- advantages
- In line with the open and close principle. You can introduce a new subscriber class without having to change the publisher code (you can easily introduce a publisher class if it’s a publisher interface).
- You can establish connections between objects at run time.
- disadvantages
- Subscribers are notified in random order.