1. Usage
- Pattern Observer – define relationship “one to many” such way that when state of object change all dependent objects notified/updated automatically.
- Pattern Observer encapsulate main component in Subject abstraction and dependent objects in Observer hierarchy.
- Observer used IN MVC as View part
This pattern used widely in User interfaces.
2. UML class diagram
3. Pros
- The Observer Pattern avoids direct object interactions and can be used when one or more objects are interested in the state changes of a given object.
- It can be used to develop loosely coupled applications maintaining object state dependencies.
- It can be used when the number of state dependent objects is not known in advance or even when the number may even change over time.
- Subject and the Observer objects can be reused separately and they can vary independently.
- The Observer Pattern can be used to develop application in layers. For example, a user interface application can contain spreadsheet, graph, and chart objects (Observers, at a higher level) that are dependent on the data from a database object (Subject, at a lower level). When the data in the database object changes all the Observers are automatically notified through the abstract operation defined in the Observer base class. Since the abstract operation is defined in the base class, the Subject need not know the concrete Observer classes and hence they are loosely coupled.
- Since all the Observers are notified through the same abstract operation, it is easy to add or remove Observers on demand.
4. Cons
- In most situations, Observers will simply be only notified about a state change. It is up to the Observer to find out what exactly has changed. However, this can be avoided by including additional information (or the Aspect of change) along with the notification. This will give some clue about the change to the Observer.
- Observer objects are totally independent and they have no knowledge on the existence of the fellow Observers. Therefore, an Observer object can change the state of the Subject (in the Update method) before even all the Observers are notified. This may result in state inconsistencies and the state change notifications will be lost.
- Whenever an Observer changes the Subjects state, all the dependent Observers are notified. If the dependency criteria is not well defined, recursive updates can easily happen. Usually, in Stair-Masters the workout program and the heart rate are mutually dependent. That is, when the program changes (say from Fat Burn to Cardio) the heart rate changes and when the heart rate range falls below or goes above a threshold limit the program automatically changes. For the sake of simplicity, this dependency criterion is not enforced in the example. Assuming that the dependency criterion is not well defined in the example, Program controller will update the Cardio Subject when the program changes and Heart rate monitor will recompute the heart rate. If the heart rate falls below or goes above the threshold level, the heart rate monitor will update the Cardio Subject to change the program, which in turn will update the Program controller and this cycle repeats. Therefore, Heart rate monitor and Program controller blindly updates the Cardio Subject, which notifies both these monitors to update themselves resulting in recursive update calls.
- Observer Pattern introduces an additional level of indirection to maintain state consistency. This increases the flexibility in the application design, but has a sure performance impact. Also, too many indirections decrease the understandability of the code.
- When the Subject is deleted, the Observers dont have a direct way to know about the deletion. Therefore, the Observers will have dangling reference to the deleted Subjects.
5. Source code
#include <iostream> #include <vector> using namespace std; class Subject { // 1. "independent" functionality vector < class Observer * > views; // 3. Coupled only to "interface" int value; public: void attach(Observer *obs) { views.push_back(obs); } void setVal(int val) { value = val; notify(); } int getVal() { return value; } void notify(); }; class Observer { // 2. "dependent" functionality Subject *model; int denom; public: Observer(Subject *mod, int div) { model = mod; denom = div; // 4. Observers register themselves with the Subject model->attach(this); } virtual void update() = 0; protected: Subject *getSubject() { return model; } int getDivisor() { return denom; } }; void Subject::notify() { // 5. Publisher broadcasts for (int i = 0; i < views.size(); i++) views[i]->update(); } class DivObserver: public Observer { public: DivObserver(Subject *mod, int div): Observer(mod, div){} void update() { // 6. "Pull" information of interest int v = getSubject()->getVal(), d = getDivisor(); cout << v << " div " << d << " is " << v / d << '\n'; } }; class ModObserver: public Observer { public: ModObserver(Subject *mod, int div): Observer(mod, div){} void update() { int v = getSubject()->getVal(), d = getDivisor(); cout << v << " mod " << d << " is " << v % d << '\n'; } }; int main() { Subject subj; DivObserver divObs1(&subj, 4); // 7. Client configures the number and DivObserver divObs2(&subj, 3); // type of Observers ModObserver modObs3(&subj, 3); subj.setVal(14); } /* Output 14 div 4 is 3 14 div 3 is 4 14 mod 3 is 2 */
Reference
- https://sourcemaking.com/design_patterns/observer/cpp/3
- http://www.codeguru.com/cpp/cpp/cpp_mfc/patterns/article.php/c837/Applying-Observer-Pattern-in-C-Applications.htm