[c++] Design Patterns: Observer Patterns

3. Observer Model (Observer Model)

Observe r model is divided into two roles: observer and listener.

Observers: Observe events; and notify listeners interested in the event; (that is, two things: registering events, regsiter messages; and publishing events, handlemessage);

Listener: Handling events;

An example model/view/control (MVC) of Observer plays an important role in the design of system development architecture. MVC realizes the decoupling of business logic and presentation layer. Of course, MVC is just an example of the observer pattern. The problem to be solved in the observer model is to establish a dependence relationship between subject and observe, and to make sure that when the "one" changes, the dependence and the "one" can also change at the same time.

The structure diagram of Observer pattern:

The subject of the target relies on its observer's attach and detach operations, and provides notify operations that synchronize the dependency with all its observers. Observer, the observer, provides an update operation. Note that the update operation of the observer does not update itself when the observer changes the target state of the subject. This update operation is delayed until the subject object notify all observers to make changes.

Use scenarios of the observer pattern:

1. When an abstract model has two aspects, one depends on the other. They can be encapsulated in separate objects so that they can be reused independently.

2. When an object changes, it needs to change other objects at the same time, without knowing how many objects need to be changed.

3. When an object must notify other objects, it cannot assume who the other objects are, that is, these objects are loosely coupled.

Simple realization of the observer:

class Listener
{
public:
	Listener(std::string name) :mname(name){}
	virtual void handleMessage(int message)const = 0;//Handling events
protected:
	std::string mname;
};
class Listener1:public Listener
{
public:
	Listener1(std::string name) :Listener(name){}
	virtual void handleMessage(int message)const
	{
		switch (message)
		{
		case 1:
			std::cout << mname << " has been solved 1 message!" << std::endl;
			break;
		case 2:
			std::cout << mname << " has been solved 2 message!" << std::endl;
			break;
		default:
			std::cout << mname << " no interested this message!" << std::endl;
			break;
		}
	}
};
class Listener2:public Listener
{
public:
	Listener2(std::string name) :Listener(name){}
	virtual void handleMessage(int message)const
	{
		switch (message)
		{
		case 2:
			std::cout << mname << " has been solved 2 message!" << std::endl;
			break;
		case 3:
			std::cout << mname << " has been solved 3 message!" << std::endl;
			break;
		default:
			std::cout << mname << " no interested this message!" << std::endl;
			break;
		}
	}
};
class Listener3:public Listener
{
public:
	Listener3(std::string name) :Listener(name){}
	virtual void handleMessage(int message)const
	{
		switch (message)
		{
		case 1:
			std::cout << mname << " has been solved 1 message!" << std::endl;
			break;
		case 3:
			std::cout << mname << " has been solved 3 message!" << std::endl;
			break;
		default:
			std::cout << mname << " no interested this message!" << std::endl;
			break;
		}
	}
};

class Observe//Observer
{
public:
	typedef std::map<int, std::vector<const Listener*>> _Mty;
	typedef std::vector<const Listener*> _Vty;
	void notify(int message)//Synchronized message 
	{
		_Mty::iterator fit = mymap.find(message);
		if (fit != mymap.end())
		{
			_Vty::iterator it = fit->second.begin();
			while (it != fit->second.end())
			{
				(*it)->handleMessage(message);
				it++;
			}
		}
	}
	void registerMessage(int message, const Listener* pls)//Registration Events
	{
		_Mty::iterator fit = mymap.find(message);
		if (fit != mymap.end())
		{
			fit->second.push_back(pls);
		}
		else
		{
			_Vty vec;
			vec.push_back(pls);
			mymap[message] = vec;
		}
	}
private:
	map<int, std::vector<const Listener*>> mymap;
};

Observer in the above code is used by our observer to Observe the event. When an event arrives, the observer sends the event to the listener who is interested in the event, and the listener processes the event.

 

The advantages of the observer:

The target and the observer are completely decoupled and can be extended independently without specific interfaces.

It's very convenient to implement cross-process, threaded observers. This benefits from the standard messaging mechanism.

Disadvantage: Time delay in performance; for a specific subject's state change, all specific observe rs must update(), i.e. business logic processing. If the observation set is too large, then there is a traversal performance problem.

Posted by djbuddhi on Mon, 19 Aug 2019 23:06:41 -0700