Changeset b760ac5


Ignore:
Timestamp:
Dec 13, 2011, 12:02:21 PM (14 years ago)
Author:
Frederik Heber <heber@…>
Children:
3324cf
Parents:
d85532
git-author:
Frederik Heber <heber@…> (12/02/11 13:13:44)
git-committer:
Frederik Heber <heber@…> (12/13/11 12:02:21)
Message:

Relay can now also relay notifications.

  • NOTE: We do not yet notify the Observables, whose update() we combine, when the Relay is destroyed. They have to signOff before by themselves (or by some other means, e.g. be destroyed before.).
Location:
src
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • src/Patterns/Observer/Relay.cpp

    rd85532 rb760ac5  
    2424#include "Assert.hpp"
    2525#include "Channels.hpp"
    26 #include "defs.hpp"
    2726#include "Notification.hpp"
    2827
     
    4847  observerLog().addMessage() << "-- Destroying Relay " << observerLog().getName(this);
    4948#endif
    50 }
    51 
     49  // killing subjects is done by Observables' dstor
     50}
     51
     52
     53
     54/** Sign on an Observer to this Observable.
     55 * Puts \a *target into Observable::callTable list.
     56 * \param *target Observer
     57 * \param priority number in [-20,20]
     58 */
     59void Relay::signOn(Observer *target, PriorityLevel priority) const
     60{
     61#ifdef LOG_OBSERVER
     62  observerLog().addMessage() << "@@ Signing on " << observerLog().getName(target)
     63      << " to "
     64      << observerLog().getName(const_cast<Observable *>(static_cast<const Observable * const>(this)));
     65#endif
     66  bool res = false;
     67  callees_t &callees = callTable[const_cast<Observable *>(static_cast<const Observable * const>(this))];
     68
     69  callees_t::iterator iter;
     70  for(iter=callees.begin();iter!=callees.end();++iter){
     71    res |= ((*iter).second == target);
     72  }
     73  if(!res)
     74    callees.insert(std::pair<int,Observer*>(priority.level,target));
     75}
     76
     77/** Sign off an Observer from this Observable.
     78 * Removes \a *target from Observable::callTable list.
     79 * \param *target Observer
     80 */
     81void Relay::signOff(Observer *target) const
     82{
     83  ASSERT(callTable.count(const_cast<Observable *>(static_cast<const Observable * const>(this))),
     84      "Relay::signOff() - called for an Observable without Observers.");
     85#ifdef LOG_OBSERVER
     86  observerLog().addMessage() << "** Signing off " << observerLog().getName(target)
     87      << " from "
     88      << observerLog().getName(const_cast<Observable *>(static_cast<const Observable * const>(this)));
     89#endif
     90  callees_t &callees = callTable[const_cast<Observable *>(static_cast<const Observable * const>(this))];
     91
     92  callees_t::iterator iter;
     93  callees_t::iterator deliter;
     94  for(iter=callees.begin();iter!=callees.end();) {
     95    if((*iter).second == target) {
     96      callees.erase(iter++);
     97    }
     98    else {
     99      ++iter;
     100    }
     101  }
     102  if(callees.empty()){
     103    callTable.erase(const_cast<Observable *>(static_cast<const Observable * const>(this)));
     104  }
     105}
     106
     107void Relay::signOn(Observer *target, size_t channelno) const
     108{
     109  Notification_ptr notification = getChannel(channelno);
     110  notification->addObserver(target);
     111}
     112
     113void Relay::signOff(Observer *target, size_t channelno) const
     114{
     115  Notification_ptr notification = getChannel(channelno);
     116  notification->removeObserver(target);
     117}
    52118
    53119/** Notify all Observers of changes.
     
    125191      Updater = publisher;
    126192      notifyAll();
     193      Updater = NULL;
    127194    }
    128195    else{
     
    135202}
    136203
    137 //Notification_ptr Relay::getChannel(size_t no) const
    138 //{
    139 //  ASSERT(NotificationChannels != NULL,
    140 //      "Relay::getChannel() - observable has no channels.");
    141 //  return NotificationChannels->getChannel(no);
    142 //}
     204/** Method for receiving specialized notifications.
     205 *
     206 * \param *publisher The \a *this we observe.
     207 * \param notification type of notification
     208 */
     209void Relay::recieveNotification(Observable *publisher, Notification_ptr notification)
     210{
     211  Updater = publisher;
     212  const Channels *myChannels = NotificationChannels[const_cast<Observable *>(static_cast<const Observable * const>(this))];
     213  ASSERT(myChannels != NULL,
     214      "Relay::recieveNotification() - this relay does not have any channels.");
     215  const size_t channelno = notification->getChannelNo();
     216  Notification_ptr mynotification = myChannels->getChannel(channelno);
     217  ASSERT(mynotification != NULL,
     218      "Relay::recieveNotification() - this relay does not have a notification no "+toString(channelno)+".");
     219  mynotification->notifyAll(Updater);
     220  Updater = NULL;
     221}
    143222
    144223/** Handles sub-observables that just got killed
  • src/Patterns/Observer/Relay.hpp

    rd85532 rb760ac5  
    3636  virtual ~Relay();
    3737
    38 //  Notification_ptr getChannel(size_t no) const;
     38  virtual void signOn(Observer *target, PriorityLevel priority = Observable::PriorityDefault) const;
     39
     40  virtual void signOff(Observer *target) const;
     41
     42  virtual void signOn(Observer *target, size_t channelno) const;
     43
     44  virtual void signOff(Observer *target, size_t channelno) const;
    3945
    4046protected:
    4147  virtual void update(Observable *publisher);
     48  virtual void recieveNotification(Observable *publisher, Notification_ptr notification);
    4249  virtual void subjectKilled(Observable *publisher);
    4350
     
    4754  //!> Current peer that called last update on us, to be passed on to Observers
    4855  Observable *Updater;
    49 //protected:
    50 //
    51 //  Channels *NotificationChannels;
    52 //
    5356};
    5457
  • src/Patterns/Observer/unittests/ObserverUnitTest.cpp

    rd85532 rb760ac5  
    7171  RelayObservable = new RelayTest;
    7272  RelayObserver = new RelayCountObserver(RelayObservable);
     73
     74  RelayNotifier = new RelayNotification;
     75  RelayNotified = new RelayNotificationObserver(RelayObservable);
    7376}
    7477
     
    8487  delete RelayObservable;
    8588  delete RelayObserver;
     89  delete RelayNotifier;
     90  delete RelayNotified;
    8691
    8792  delete observer1;
     
    276281}
    277282
     283void ObserverTest::relayNotificationTest()
     284{
     285  observerLog().enableLogging();
     286
     287  // sign on some observables to the relay
     288  notificationObservable->signOn(RelayNotifier, NotificationObservable::Operation1Notify);
     289  notificationObservable->signOn(RelayNotifier, NotificationObservable::Operation2Notify);
     290  notificationObservable->signOn(notificationObserver1, NotificationObservable::Operation1Notify);
     291
     292  RelayNotifier->signOn(RelayNotified, NotificationObservable::Operation1Notify);
     293
     294  // operation1
     295  notificationObservable->operation1();
     296  CPPUNIT_ASSERT(RelayNotified->wasNotified);
     297  CPPUNIT_ASSERT(notificationObserver1->wasNotified);
     298
     299  RelayNotified->wasNotified=false;
     300
     301  // operation2
     302  notificationObservable->operation2();
     303  CPPUNIT_ASSERT(!RelayNotified->wasNotified);
     304  CPPUNIT_ASSERT(notificationObserver1->wasNotified);
     305
     306  // signOff relay from 1 and operation1
     307  notificationObserver1->wasNotified=false;
     308  notificationObservable->signOff(RelayNotifier, NotificationObservable::Operation1Notify);
     309
     310  notificationObservable->operation1();
     311  CPPUNIT_ASSERT(!RelayNotified->wasNotified);
     312  CPPUNIT_ASSERT(notificationObserver1->wasNotified);
     313
     314  // test kill subject
     315  delete RelayNotified;
     316  RelayNotified = NULL; // delete in tearDown is allowed for NULL
     317  notificationObservable->operation1();
     318  delete notificationObservable;
     319  notificationObservable = NULL; // delete in tearDown is allowed for NULL
     320
     321  observerLog().disableLogging();
     322}
     323
    278324void ObserverTest::CircleDetectionTest() {
    279325  std::cout << std::endl << "Warning: the next test involved methods that can produce infinite loops." << std::endl;
  • src/Patterns/Observer/unittests/ObserverUnitTest.hpp

    rd85532 rb760ac5  
    2828class NotificationObservable;
    2929class RelayCountObserver;
     30class RelayNotification;
     31class RelayNotificationObserver;
    3032
    3133class ObserverTest :  public CppUnit::TestFixture
     
    4042  CPPUNIT_TEST ( iteratorTest );
    4143  CPPUNIT_TEST ( relayTest );
     44  CPPUNIT_TEST ( relayNotificationTest );
    4245  CPPUNIT_TEST ( CircleDetectionTest );
    4346  CPPUNIT_TEST_SUITE_END();
     
    5558  void iteratorTest();
    5659  void relayTest();
     60  void relayNotificationTest();
    5761  void CircleDetectionTest();
    5862
     
    7680  RelayTest *RelayObservable;
    7781  RelayCountObserver *RelayObserver;
     82  RelayNotification *RelayNotifier;
     83  RelayNotificationObserver *RelayNotified;
    7884};
    7985
  • src/Patterns/Observer/unittests/stubs/ObserverStub.cpp

    rd85532 rb760ac5  
    239239{}
    240240
     241/************ RelayNotification ***************/
     242
     243RelayNotification::RelayNotification() :
     244    Relay(std::string("RelayTest"))
     245{
     246  Channels *OurChannel = new Channels();
     247  NotificationChannels.insert( std::make_pair(this, OurChannel) );
     248  OurChannel->addChannel(NotificationObservable::Operation1Notify);
     249  OurChannel->addChannel(NotificationObservable::Operation2Notify);
     250}
     251
     252RelayNotification::~RelayNotification()
     253{}
     254
    241255/************ RelayCountObserver ***************/
    242256
     
    259273}
    260274
     275/********* RelayNotificationObserver ***********/
     276
     277RelayNotificationObserver::RelayNotificationObserver(const Observable * const _relay) :
     278  Observer("RelayNotificationObserver"),
     279  wasNotified(false),
     280  relay(_relay)
     281{}
     282
     283RelayNotificationObserver::~RelayNotificationObserver()
     284{}
     285
     286void RelayNotificationObserver::update(Observable*){}
     287void RelayNotificationObserver::subjectKilled(Observable*){}
     288void RelayNotificationObserver::recieveNotification(Observable *publisher, Notification_ptr notification){
     289  // check that we are not called by the relay itself
     290  CPPUNIT_ASSERT(publisher != relay);
     291  wasNotified = true;
     292}
     293
  • src/Patterns/Observer/unittests/stubs/ObserverStub.hpp

    rd85532 rb760ac5  
    148148};
    149149
     150class RelayNotification : public Relay
     151{
     152public:
     153  RelayNotification();
     154  ~RelayNotification();
     155private:
     156};
     157
     158class RelayNotificationObserver : public Observer {
     159public:
     160  RelayNotificationObserver(const Observable * const _relay);
     161  virtual ~RelayNotificationObserver();
     162
     163  void update(Observable*);
     164  void subjectKilled(Observable*);
     165  void recieveNotification(Observable *publisher, Notification_ptr notification);
     166
     167  bool wasNotified;
     168private:
     169  const Observable * const relay;
     170};
     171
    150172#endif /* OBSERVERSTUB_HPP_ */
  • src/documentation/patterns/observer.dox

    rd85532 rb760ac5  
    2828 * updating many of its internal sub-observables. This means the update is not passed, if
    2929 * it is produced while the main-observable itself is within any Observation block.
     30 *
     31 * \section pattern-observer-howtos Howto
     32 *
     33 *  Below you find various howtos to guide you through how to use the various
     34 *  observer patterns.
     35 *
     36 * \section pattern-observer-howtos-observer Observers
     37 *
     38 *  \todo write howto for using an Observer
     39 *
     40 * \section pattern-observer-howtos-observables Observables
     41 *
     42 *  \todo write howto for using an Observable
     43 *
     44 * \section pattern-observer-howtos-relay Relays
     45 *
     46 *  Lets us assume that you want to observe all instances of class "foo".
     47 *  In order to create a Relay you have to do the following:
     48 *  -# Create a new class "bar" that inherits the Relay pattern.
     49 *  \code
     50 *    #include "CodePatterns/Relay.hpp"
     51 *    class bar : public Relay {
     52 *    ...
     53 *    };
     54 *  \endcode
     55 *  -# In the constructor bar::bar() create a Channels object for your Relay and
     56 *     add a channel for each of foo's channels, use foo's enum for this:
     57 *   \code
     58 *     bar::bar() {
     59 *      Channels *OurChannel = new Channels();
     60 *      NotificationChannels.insert( std::make_pair(this, OurChannel) );
     61 *      OurChannel->addChannel(foo::Notification1);
     62 *      OurChannel->addChannel(foo::Notification2);
     63 *      ...
     64 *     }
     65 *   \endcode
     66 *   -# Someplace else you have add all Observers that need to check on all
     67 *      instances of "foo" to be signed on.
     68 *    \code
     69 *    bar barInstance;
     70 *    ... someObserverInstance;
     71 *    barInstance.signOn(someObserverInstance);
     72 *    \endcode
     73 *   -# ... or maybe just for a specific channel of foo.
     74 *    \code
     75 *    bar barInstance;
     76 *    ... someObserverInstance;
     77 *    barInstance.signOn(someObserverInstance, foo::Notification1);
     78 *    \endcode
     79 *
     80 *
     81 * \date 2011-12-01
    3082 */
    3183
Note: See TracChangeset for help on using the changeset viewer.