source: src/Patterns/Observer.hpp@ 70672e3

Last change on this file since 70672e3 was 70672e3, checked in by Frederik Heber <heber@…>, 15 years ago

Added config.h to all header files.

  • Property mode set to 100644
File size: 8.1 KB
Line 
1/*
2 * Observer.hpp
3 *
4 * Created on: Jan 19, 2010
5 * Author: crueger
6 */
7
8#ifndef OBSERVER_HPP_
9#define OBSERVER_HPP_
10
11// include config.h
12#ifdef HAVE_CONFIG_H
13#include <config.h>
14#endif
15
16#include <map>
17#include <set>
18#include <string>
19#include <sstream>
20
21/**
22 * Basic structure for the observer pattern
23 *
24 * Observers register themselves with the observables to be notified when something changes.
25 * In the Observable code that changes, attributes should be started with OBSERVE;. This macro
26 * locks the observer mechanism while changes are done. At the end of the scope in which the
27 * macro was placed the lock is released. When the last lock is released all changes are
28 * propagated to the observers.
29 *
30 * Each observerable can have sub-observables. When one of these sub-observables changes and
31 * notifies its observers the observable that contains them will also notify its observers.
32 * This passing on of updates is blocked, when the main-observable is in the process of
33 * updating many of its internal sub-observables. This means the update is not passed, if
34 * it is produced while the main-observable itself is within any Observation block.
35 */
36
37// Deactivate any logging when we are not in debug mode
38#ifdef NDEBUG
39#undef LOG_OBSERVER
40#endif
41
42class Observable;
43class Notification;
44
45// Pointers to notifications are used for unique identification
46// using this typedef makes it hard for others to mess up this
47// identification process
48typedef Notification *const Notification_ptr;
49
50template<class _Set>
51class ObservedIterator;
52
53/**
54 * An Observer is notified by all Observed objects, when anything changes.
55 *
56 * If a simple change is done to an Object the Obervable will call the update() method
57 * of all signed on observers, passing itself as a parameter for identification. The
58 * Observers should then react to the changes and update themselves accordingly.
59 *
60 * If an observed Object is destroyed it will call the subjectKilled() method
61 * of all signed on Observers, again passing itself as a parameter for identification.
62 * The Observers should handle the destruction of an observed Object gracefully, i.e.
63 * set themselves inactive, display something else, etc. There is no need
64 * to sign of from the dying object, since this will be handled by the Observable destructor.
65 */
66class Observer
67{
68 friend class Observable;
69 friend class Notification;
70 template<class> friend class ObservedIterator;
71
72 // indicates the constructor called from Observables
73 struct BaseConstructor{};
74
75public:
76 Observer(BaseConstructor);
77 Observer(std::string);
78 virtual ~Observer();
79
80protected:
81 /**
82 * This method is called upon changes of the Observable
83 */
84 virtual void update(Observable *publisher)=0;
85
86 /**
87 * This method is called when a special named change
88 * of the Observable occured
89 */
90 virtual void recieveNotification(Observable *publisher, Notification_ptr notification);
91
92 /**
93 * This method is called when the observed object is destroyed.
94 */
95 virtual void subjectKilled(Observable *publisher)=0;
96};
97
98/**
99 * An Observable implements all neccessary method for being observed.
100 *
101 * That is, it provides methods for signing on and of from an
102 * Observable that can be used by any observer. The actual
103 * observer-mechanism is handled at a central static place
104 * to avoid memory issues when many observable are around but only few
105 * are actually observed.
106 */
107class Observable : public Observer {
108public:
109 Observable(std::string _name);
110 virtual ~Observable();
111
112 /**
113 * Sign an Observer on to this Observable. The Observer will be notified
114 * whenever something inside the Observable changes. The Observer can
115 * assign itself a priority for the changes in the range of -20:+20.
116 * The Observer with lower priority will be called before the others,
117 * same as with Unix nice-levels. This can be used when an Object
118 * contains other objects that observe it (derived values), and these objects have
119 * to recalculate their states before the changes should be propageted to the
120 * UI. A default priority of 0 should be fine in most cases, since there is
121 * ussually no need to order the update sequence.
122 */
123 virtual void signOn(Observer *target, int priority=0);
124
125 /**
126 * Sign of a previously signed on Observer. After this no more
127 * updates will be recieved from that observer.
128 */
129 virtual void signOff(Observer *target);
130
131 /**
132 * Sign on for specialized notifications
133 */
134 virtual void signOn(Observer *target, Notification_ptr notification);
135
136 /**
137 * Stop receiving a specialized notification
138 */
139 virtual void signOff(Observer *target, Notification_ptr notification);
140
141 /**
142 * Ask an Observer if it is currently in a blocked state, i.e. if
143 * Changes are in Progress, that are not yet published.
144 */
145 virtual bool isBlocked();
146
147protected:
148 virtual void update(Observable *publisher);
149 virtual void subjectKilled(Observable *publisher);
150
151 virtual void notifyAll();
152protected:
153// Observer mechanism is done from a static central place
154 /**
155 * Internal method.
156 * Do not call directly. Use OBSERVE macro instead
157 */
158 static void start_observer_internal(Observable *publisher);
159 /**
160 * Internal method.
161 * Do not call directly. Use OBSERVE macro instead
162 */
163 static void finish_observer_internal(Observable *publisher);
164
165 static void enque_notification_internal(Observable *publisher, Notification_ptr notification);
166
167private:
168 typedef std::multimap<int,Observer*> callees_t;
169 typedef std::set<Notification*> notificationSet;
170 static std::map<Observable*, int> depth;
171 static std::map<Observable*,callees_t> callTable;
172 static std::map<Observable*,notificationSet> notifications;
173 static std::set<Observable*> busyObservables;
174
175 //! @cond
176 // Structure for RAII-Style notification
177public:
178 /**
179 * This structure implements the Observer-mechanism RAII-Idiom.
180 * It triggers certain functions on creation and destruction so that
181 * Observer mechanisms can be linked to scope block.
182 */
183 class _Observable_protector {
184 public:
185 _Observable_protector(Observable *);
186 _Observable_protector(const _Observable_protector&);
187 ~_Observable_protector();
188 private:
189 Observable *protege;
190 };
191 //! @endcond
192};
193
194class Notification {
195 friend class Observable;
196public:
197 Notification(Observable *_owner);
198 virtual ~Notification();
199protected:
200
201 void addObserver(Observer *target);
202 void removeObserver(Observer *target);
203
204 void notifyAll();
205private:
206 Observable * const owner;
207 std::set<Observer*> targets;
208};
209
210#ifdef LOG_OBSERVER
211
212/**
213 * This class is used to log the working of the observer mechanism
214 *
215 * TODO: make this conditional dependent on compiler Flag.
216 */
217class ObserverLog{
218 friend class Observable;
219 friend class Observer;
220 template <typename> friend class Cacheable;
221public:
222 ObserverLog();
223 ~ObserverLog();
224 std::string getLog(); // get everything that has been logged
225 std::string getName(void*); // get the name of an actor
226 bool isObservable(void*);
227private:
228 int count; // number to reference each actor in this framework
229 std::map<void*,std::string> names; // List of names assigned to actors
230 std::set<void*> observables; // List of pointers to Observables. Needed to distinguish Observers and Observables
231 void addName(void*, std::string); // Assign a name to an Actor
232 void addObservable(void*);
233 void deleteName(void*); // delete the name of an Actor
234 void deleteObservable(void*);
235 std::stringstream &addMessage(int depth=0); // Add a Message to the logging
236 std::stringstream log; // The internal log object
237};
238
239ObserverLog &observerLog();
240
241#endif
242
243// extra macro is necessary to work with __LINE__
244#define PASTE(a,b) PASTE_HELPER(a,b)
245#define PASTE_HELPER(a,b) a ## b
246#define OBSERVE Observable::_Observable_protector PASTE(_scope_obs_protector_,__LINE__)(this)
247#define NOTIFY(notification) do{Observable::enque_notification_internal(this,notification);}while(0)
248#define LOCK_OBSERVABLE(observable) Observable::_Observable_protector PASTE(_scope_obs_protector_,__LINE__)(&(observable))
249
250#endif /* OBSERVER_HPP_ */
Note: See TracBrowser for help on using the repository browser.