The observer pattern is a software design pattern in which an object, named the Subject, maintains a list of its dependents, called Observers, and notifies them automatically of any state changes, usually by calling one of their methods.
Used for implementing distributed event handling systems, in event driven software.
In those systems, the subject is usually named a stream of events or stream source of events, while the observers are called sinks of events.
Most modern programming-languages comprise built-in “event” constructs implementing the observer-pattern components.
While not mandatory, most observers implementations would use background threads listening for subject-events and other support mechanisms provided by the kernel (Linux epoll, …).
The Observer pattern captures the lion’s share of the Model-View-Controller architecture.
Problems Addressed
The Observer pattern addresses the following problems:
A one-to-many dependency between objects should be defined without making the objects tightly coupled.
In some scenarios, Tightly coupled objects can be hard to implement, and hard to reuse because they refer to and know about many different objects with different interfaces.
In other scenarios, tightly coupled objects can be a better option since the compiler will be able to detect errors at compile-time and optimize the code at the CPU instruction level.
It should be ensured that when one object changes state, an open-ended/any number of dependent objects are updated automatically.
It should be possible that one object can notify an open-ended number of other objects.
A large monolithic design does not scale well as new graphing or monitoring requirements are levied.
Solution with Subject & Observers
Observer pattern defines Subject and Observer objects.
When a subject changes state, all registered observers are notified and updated automatically (and probably asynchronously).
Responsibility of Subject:
Maintain a list of observers
Notify them of state changes by calling their update() operation.
Responsibility of Observers:
Register/Unregister themselves on a subject (to get notified of state changes)
Update their state when notified (synchronize their state with the subject’s state).
This makes subject and observers loosely coupled.
Subject and observers have no explicit knowledge of each other.
Observers can be added and removed independently at run-time.
This notification-registration interaction is also known as publish-subscribe.
Coupled Vs Pub-Sub implementations
Tightly Coupled Implementation
Typically, the observer pattern is implemented so the subject being observed is part of the object for which state changes are being observed.
This type of implementation forces both the observers and the subject to be aware of each other and have access to their internal parts, creating possible issues of scalability, speed, message recovery and maintenance, the lack of flexibility in conditional dispersion, and possible hindrance to desired security measures.
Pub-Sub Implementations:
In some (non-polling) implementations of the publish-subscribe pattern (aka the pub-sub pattern), this is solved by creating a dedicated message queue server (and sometimes an extra message handler object) as an extra stage between the observer and the object being observed, thus decoupling the components.
In these cases, the message queue server is accessed by the observers with the observer pattern, subscribing to certain messages knowing only about the expected message (or not, in some cases), while knowing nothing about the message sender itself; the sender also may know nothing about the observers.
Other implementations of the publish-subscribe pattern, which achieve a similar effect of notification and communication to interested parties, do not use the observer pattern at all.
Limitations
Observer Pattern as described in GoF is very basic and does not address:
Removing interest in changes to the observed "subject" (Unregister)
Special logic to be done by the observed “subject” before or after notifying the observers.
Recording of change notifications sent
Guaranteeing that notifications are being received.
These concerns are typically handled in message queueing systems of which the observer pattern is only a small part.
Related patterns:
Publish–subscribe pattern
Mediator
Singleton
UML Class & Sequence diagrams
In the above UML class diagram,
Subject class does not update the state of dependent objects directly.
Instead, Subject refers to the Observer interfaceupdate() for updating state, which makes the Subject independent of how the state of dependent objects is updated.
The Observer1 and Observer2 classes implement the Observer interface and synchronize their state with subject’s state.
The UML sequence diagram shows the run-time interactions:
The Observer1 and Observer2 objects call attach(this) on Subject1 to register themselves.
Assuming that the state of Subject1 changes, Subject1 calls notify() on itself.
notify() calls update() on the registered Observer1 and Observer2 objects, which request the changed data (getState()) from Subject1 to update (synchronize) their state.
The protocol described above specifies a pull interaction model. Instead of the Subject pushing what has changed to all Observers, each Observer is responsible for pulling its particular "window/topic of interest" from the Subject.
The push model compromises reuse, while the pull model is less efficient.
// The number and type of "Observer" objects are hard-wired in the Subject class.// The user has no ability to add more observers without modifying Subject class.classDivObserver{intm_div;public:DivObserver(intdiv){m_div=div;}// parameterized constructorvoidupdate(intval){cout<<val<<" div "<<m_div<<" is "<<val/m_div<<'\n';}};classModObserver{intm_mod;public:ModObserver(intmod){m_mod=mod;}// parameterized constructorvoidupdate(intval){cout<<val<<" mod "<<m_mod<<" is "<<val%m_mod<<'\n';}};classSubject{intm_value;DivObserverm_div_obj;// Composite ObjectsModObserverm_mod_obj;public:Subject():m_div_obj(4),m_mod_obj(3){}// invoking parameterized constructorsvoidset_value(intvalue){m_value=value;notify();}voidnotify(){m_div_obj.update(m_value);// calling Hard-wired objects' methodsm_mod_obj.update(m_value);}};intmain(void){Subjectsubj;subj.set_value(14);}// Output:// 14 div 4 is 3// 14 mod 3 is 2
// The Subject class is now decoupled from the number and type of Observer objects.// The client/user has asked for two DivObserver delegates (each configured differently),// and one ModObserver delegate.classObserver{// Abstract classpublic:virtualvoidupdate(intvalue)=0;// Pure Virtual Method};classSubject{intm_value;vectorm_views;// List of Observerspublic:voidattach(Observer*obs){m_views.push_back(obs);// Add observers to list}voidset_val(intvalue){m_value=value;notify();// notify change}voidnotify(){for(inti=0;i<m_views.size();++i)m_views[i]->update(m_value);// Push notification to each observer// invoke `update()` of respective concrete sub-class}};classDivObserver:publicObserver{// Concrete sub-class of Observerintm_div;public:DivObserver(Subject*model,intdiv){// Parameterized constructormodel->attach(this);// Subject/Observable object as inputm_div=div;}/* virtual */voidupdate(intv){// Implement Pure-Virtual methodcout<<v<<" div "<<m_div<<" is "<<v/m_div<<'\n';}};classModObserver:publicObserver{// sub-class of Observer Abstract classintm_mod;public:ModObserver(Subject*model,intmod){// Parameterized constructormodel->attach(this);// Subject/Observable object as inputm_mod=mod;}/* virtual */voidupdate(intv){// Implement Pure-Virtual methodcout<<v<<" mod "<<m_mod<<" is "<<v%m_mod<<'\n';}};intmain(void){Subjectsubj;DivObserverdivObs1(&subj,4);// multiple observers of same sub-classDivObserverdivObs2(&subj,3);// Require no modification to any implementationModObservermodObs3(&subj,3);// i.e. Loosely-coupled implementationsubj.set_val(14);// state change}// Output:// 14 div 4 is 3// 14 div 3 is 4// 14 mod 3 is 2
[ToDo: Observer vs Mediator vs Command vs Chain of Responsibility]