>

Tuesday, 15 December 2015

Observer Pattern

Observer:

Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically

Motivation:
The need to maintain consistency between related objects without making Classes tightly coupled.

Applicability
Use the Observer pattern in any of the following situations:
1.) When an abstraction has two aspects, one dependent on the other. Encapsulating these aspects in separate objects lets you vary and reuse them independently.
2.) When a change to one object requires changing others
3.)  When an object should be able to notify other objects without making assumptions about those objects.


Class Diagram:


Participants
Subject:Keeps track of its observers.Provides an interface for attaching and detaching Observer objects
Observer:Defines an interface for update notification
ConcreteSubject:The object being observed Stores state of interest to ConcreteObserver objects.Sends a notification to its observers when its state changes
ConcreteObserver:The observing object stores state that should stay consistent with the subject's Implements the Observer update interface to keep its state consistent with the subject's

In the topic class there are three methods ..
Attach(email id) which takes an email id as an argument
Detach(email id) which takes an email id as an argument
Notify()
The implementation of subcribe method is just three lines of code, whatever email id is passed to the method, blindly add it to the collection.
Attach(observer)
{
      Collection.add(emailid);
}
The implementation of unsubscribe method is again three lines of code, whatever email id is passed to this method, blindly add it to the collection
UnSubscribe(String emailid)
{
       Collection.remove(emailid);
}
The implementation of notify method is again three lines of code, what ever email ids are there in the collection, blindly send a email to each one of them.
notify()
{
      For(all email ids in the collection)
     {
       Blindly send the email to all the email ids in the collection.
     }
}


Sequence Diagram:




Benefits:
a) Minimal coupling between the Subject and the Observer
b) Can reuse subjects without reusing their observers and vice versa
c) Observers can be added without modifying the subject
d) All subject knows is its list of observers
e) Subject does not need to know the concrete class of an observer, just that each observer implements the update interface
f) Subject and observer can belong to different abstraction layers
g) Support for event broadcasting
  Subject sends notification to all subscribed observers
  Observers can be added/removed at any time



Observer pattern (Before and After)

class DivObserver
{
    int m_div;
  public:
    DivObserver(int div)
    {
        m_div = div;
    }
    void update(int val)
    {
        cout << val << " div " << m_div << " is " << val / m_div << '\n';
    }
};

class ModObserver
{
    int m_mod;
  public:
    ModObserver(int mod)
    {
        m_mod = mod;
    }
    void update(int val)
    {
        cout << val << " mod " << m_mod << " is " << val % m_mod << '\n';
    }
};

class Subject
{
    int m_value;
    DivObserver m_div_obj;
    ModObserver m_mod_obj;
  public:
    Subject(): m_div_obj(4), m_mod_obj(3){}
    void set_value(int value)
    {
        m_value = value;
        notify();
    }
    void notify()
    {
        m_div_obj.update(m_value);
        m_mod_obj.update(m_value);
    }
};

int main()
{
  Subject subj;
  subj.set_value(14);
}



Example:

class Observer
{
  public:
    virtual void update(int value) = 0;
};

class Subject
{
    int m_value;
    vector m_views;
  public:
    void attach(Observer *obs)
    {
        m_views.push_back(obs);
    }
    void set_val(int value)
    {
        m_value = value;
        notify();
    }
    void notify()
    {
        for (int i = 0; i < m_views.size(); ++i)
          m_views[i]->update(m_value);
    }
};

class DivObserver: public Observer
{
    int m_div;
  public:
    DivObserver(Subject *model, int div)
    {
        model->attach(this);
        m_div = div;
    }
     /* virtual */void update(int v)
    {
        cout << v << " div " << m_div << " is " << v / m_div << '\n';
    }
};

class ModObserver: public Observer
{
    int m_mod;
  public:
    ModObserver(Subject *model, int mod)
    {
        model->attach(this);
        m_mod = mod;
    }
     /* virtual */void update(int v)
    {
        cout << v << " mod " << m_mod << " is " << v % m_mod << '\n';
    }
};

int main()
{
  Subject subj;
  DivObserver divObs1(&subj, 4);
  DivObserver divObs2(&subj, 3);
  ModObserver modObs3(&subj, 3);
  subj.set_val(14);
}

Example2: News Agency
Lets' take the example of a news agency. A news agency gathers news and publishes them to different subscribers. We need to create a framework for and agency to be able to inform immediately, when event occurs, its subscribers about the event. The subscribers can receive the news in different ways: Emails, SMS,... The solution need to be extensively enough to support new types of subscribers (maybe new communication technologies will appear).






0 comments:

Post a comment