Overview | Modules | Class Hierarchy | Classes | Members

# Observer Class Reference
[Observable]

Observer is the base class for the implementation of an Observbale Observer. More...

`#include <Observable.h>`

## Detailed Description

Observer is the base class for the implementation of an Observbale Observer.

All Observable Observer must derivate from tat class. The update function will be call each time an Observable receive a notification. The event received in parameter is an object not a reference, thus it is not possible to dynamic_cast it. Only the type of the Event can be used by an Observer. The event send to the Observer are of two types (DELETE or MODIFICATION), the DELETE event is always directly sent when the Observable is deleted. For the MODIFICATION event, the event can be delayed according to the observable hold unhold state. In case of hold/unhold of events, the Observer receive only the last event. It means that if there is 100 Event::MODFICICATION between the hold/unhold the Observer receive only one events after the unhold.

On the destruction of an Observer, there is no need to remove it from the Observable it is observing. The OLOObject manage automatically disconnection and coherency.

Observer are often use to enable updates of visualized elements. The hold/unhold mechanism prevents from redisplaying too many times the view, when large number of modifications are done. The hold/unhold mechanism is global thus all the observers are holded simultaneously when holdObservers function is called.

The update function is a call back function, it is invoked by the Observable himself. Thus it is lot allowed to delete the sender Observable during an update. Even if it is permitted, usually it is not a good idea to delete any existing Observable during an update. Deleting an Onlooker is safe and is well managed by the mechanism.

All modification of the OLOObject (creation, destruction, connections), are allowed during an update.

Warning:
  Destruction of the Observable during an update will raise an OLOException.

See also:
  Observable
  Event
  Observer

That simple example demonstrates the use of an observer to maintain a set of points that we want to display (here on stdout).

     class Point : public Observable {
     public:
         ~Point() {
           //observableDeleted();
         }
         void setXY(const double x, const double y);
         void getXY(double &x, double &y) const {
             x = _x;
             y = _y;
         }
     private:
         double _x, _y;
     };

     class PointEvent : public Event {
     public:
         PointEvent(const Point &p, double px, double py):
                 Event(p, Event::MODIFICATION), prevX(px), prevY(py) {
         }
         double prevX, prevY;
     };

     void Point::setXY(const double x, const double y) {
         PointEvent ev(*this, _x, _y);
         _x = x;
         _y = y;
         if (hasOnlookers())
             notify(ev);
     }

     class PointsViewer : public Observer {
     public:
         void update(const vector<Event> &evs) {
             for (size_t i=0; i< evs.size(); ++i)
                 if (evs[i].type() == Event::DELETE)  {
                 points.erase(reinterpret_cast<Point *>(evs[i].sender()));
                 cout << "PointsViewer::Point has been deleted :" << reinterpret_cast<Point *>(evs[i].sender()) << endl << flush;
                 cout << "PointsViewer::updating view : ";
                 updateView();
                 return;
             }
             cout << "PointsViewer::objects modified : " << evs.size() << " updating view : ";
             updateView();
         }
         void addPoint(Point& p) {
             points.insert(&p);
             p.addOnlooker(*this);
             cout << "PointsViewer::point added : " << &p << endl;
         }
         void updateView() {
             for (set<const Point *>::const_iterator it = points.begin(); it != points.end(); ++it) {
                 double x,y;
                 (*it)->getXY(x, y);
                 cout << "(" << x << "," << y << ")";
             }
             cout << endl;
         }

     private:
         set<const Point *> points;
     };

     class PointListener : public Listener {
     public:
         void update(const Event &ev) {
             if (ev.type() == Event::DELETE)  {
                 cout << "PointListener::Point has been deleted : " << reinterpret_cast<Point *>(ev.sender()) << endl << flush;
                 return;
             }
             const PointEvent *event = dynamic_cast<const PointEvent *>(&ev);
             if (event) {
                 Point *p = reinterpret_cast<Point *>(ev.sender());
                 double x,y;
                 p->getXY(x, y);
                 cout << "PointListener::Point change (" << event->prevX << "," << event->prevY << ") ==> (" << x << "," << y << ")" << endl << flush;
             }
         }
     };

     int main() {
         Point *point[8];
         PointsViewer pv;
         PointListener pl;
         for (int i=0; i < 8; ++i) {
             point[i] = new Point();
             point[i]->setXY(i,i);
             pv.addPoint(*point[i]);
         }
         point[4]->addOnlooker(pl);
         pv.updateView();
         Observable::holdObservers();//all observers are holded;
         for (int i=0; i < 4; ++i) {
             delete point[i]; //pv receive 4 DELETE events (ie 4 call to update function);
         }
         for (int j = 0; j<5; ++j) {
             for (int i=4; i < 8; ++i) {
                 point[i]->setXY(i, j); //no event sent to pv
             }
         }
         Observable::unholdObservers(); //only one call to pointViewer::update with the 4 last event sent by the 4 observed points
         for (int i=4; i < 8; ++i) {
             delete point[i]; //pv receive 4 DELETE events (ie 10 call to update function);
         }
         return EXIT_SUCCESS;
     }

Tulip Software by LaBRI Visualization Team 2001 - 2012